multisite-cms-mcp 1.0.0

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.
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConversionGuide = getConversionGuide;
4
+ const SECTIONS = {
5
+ analysis: `# Phase 1: Website Analysis (MANDATORY)
6
+
7
+ Before writing ANY code, complete this analysis:
8
+
9
+ ## 1.1 Map ALL URLs
10
+ Visit every page and document the exact URL structure:
11
+ \`\`\`
12
+ / (Homepage)
13
+ /about or /about-us or /company
14
+ /services or /what-we-do
15
+ /contact or /get-in-touch
16
+ /blog or /news or /resources or /insights
17
+ /blog/post-slug
18
+ /team or /our-team
19
+ \`\`\`
20
+
21
+ ## 1.2 Categorize Each Page
22
+
23
+ **Page Types:**
24
+ - **Static** - Fixed content (/, /about, /contact)
25
+ - **List** - Shows multiple items (/blog, /team)
26
+ - **Detail** - Single item from a list (/blog/my-post)
27
+
28
+ ## 1.3 Map Content Semantically
29
+
30
+ Match by CONTENT TYPE, not by what the site calls it:
31
+
32
+ - Time-stamped articles with authors → **Blog Posts**
33
+ (even if called "Insights", "News", "Resources", "Articles")
34
+
35
+ - Staff/employee profiles → **Team**
36
+ (even if called "Leadership", "Our People", "About Us")
37
+
38
+ - Downloadable files → **Downloads**
39
+ (even if called "Resources", "Library", "Documents")
40
+
41
+ - Content writers → **Authors**
42
+ (people credited on articles)
43
+
44
+ ## 1.4 Document Assets
45
+
46
+ List all asset locations:
47
+ \`\`\`
48
+ CSS: /css/*.css, /styles/*.css
49
+ JS: /js/*.js, /scripts/*.js
50
+ Images: /images/*, /assets/img/*
51
+ Fonts: Google Fonts links, /fonts/*
52
+ \`\`\`
53
+
54
+ ## 1.5 Critical Rule
55
+
56
+ **PRESERVE ORIGINAL URLs**
57
+
58
+ If the site uses \`/resources\` for articles, keep \`/resources\`.
59
+ Do NOT change it to \`/blog\`.
60
+
61
+ Use the manifest's path configuration to maintain original URLs.`,
62
+ structure: `# Package Structure
63
+
64
+ Create a ZIP file with this exact structure:
65
+
66
+ \`\`\`
67
+ website-package.zip
68
+ ├── manifest.json # Required: Defines pages and CMS templates
69
+ ├── public/ # Static assets (CSS, JS, images, fonts)
70
+ │ ├── css/
71
+ │ │ └── style.css
72
+ │ ├── js/
73
+ │ │ └── main.js
74
+ │ └── images/
75
+ │ └── logo.png
76
+ ├── pages/ # HTML pages (static content)
77
+ │ ├── index.html
78
+ │ ├── about.html
79
+ │ └── contact.html
80
+ └── templates/ # CMS templates (dynamic content)
81
+ ├── blog_index.html
82
+ ├── blog_post.html
83
+ ├── team.html
84
+ └── downloads.html
85
+ \`\`\`
86
+
87
+ ## Folder Rules
88
+
89
+ ### public/
90
+ - ALL assets go here (CSS, JS, images, fonts)
91
+ - Maintains subfolder structure
92
+ - Referenced as \`/public/...\` in HTML
93
+
94
+ ### pages/
95
+ - Static HTML pages
96
+ - One file per page
97
+ - Use data-edit-key for editable text
98
+
99
+ ### templates/
100
+ - CMS-powered pages
101
+ - Use {{tokens}} for dynamic content
102
+ - Named by collection type`,
103
+ manifest: `# manifest.json Configuration
104
+
105
+ ## Basic Structure
106
+
107
+ \`\`\`json
108
+ {
109
+ "pages": [
110
+ {
111
+ "path": "/",
112
+ "file": "pages/index.html",
113
+ "title": "Home",
114
+ "editable": true
115
+ }
116
+ ],
117
+ "cmsTemplates": {
118
+ "blogIndex": "templates/blog_index.html",
119
+ "blogIndexPath": "/blog",
120
+ "blogPost": "templates/blog_post.html",
121
+ "blogPostPath": "/blog",
122
+ "team": "templates/team.html",
123
+ "teamPath": "/team",
124
+ "downloads": "templates/downloads.html",
125
+ "downloadsPath": "/downloads"
126
+ },
127
+ "defaultHeadHtml": "<!-- fonts, meta tags -->"
128
+ }
129
+ \`\`\`
130
+
131
+ ## Page Configuration
132
+
133
+ Each page needs:
134
+ - \`path\` - The URL (must start with /)
135
+ - \`file\` - Path to HTML file in pages/
136
+ - \`title\` - Page title for CMS
137
+ - \`editable\` - Enable inline editing (optional)
138
+
139
+ ## CMS Template Paths
140
+
141
+ **Path properties control URL routing:**
142
+
143
+ - \`blogIndexPath: "/resources"\` → Blog listing at /resources
144
+ - \`blogPostPath: "/resources"\` → Posts at /resources/post-slug
145
+ - \`teamPath: "/about/team"\` → Team at /about/team
146
+ - \`downloadsPath: "/library"\` → Downloads at /library
147
+
148
+ **IMPORTANT:** Match paths to the original site's URLs!
149
+
150
+ ## Custom Collection Paths
151
+
152
+ For dynamic collections beyond the built-ins:
153
+
154
+ \`\`\`json
155
+ {
156
+ "cmsTemplates": {
157
+ "collectionPaths": {
158
+ "products": "/shop",
159
+ "case-studies": "/work"
160
+ }
161
+ }
162
+ }
163
+ \`\`\``,
164
+ templates: `# Template Creation Guide
165
+
166
+ ## Template Types
167
+
168
+ 1. **Index Templates** - List pages (blog_index.html)
169
+ 2. **Detail Templates** - Single item pages (blog_post.html)
170
+ 3. **Static Pages** - Fixed content with data-edit-key
171
+
172
+ ## Index Template Pattern
173
+
174
+ \`\`\`html
175
+ <main class="blog-page">
176
+ <h1 data-edit-key="blog-title">Blog</h1>
177
+
178
+ <div class="posts-grid">
179
+ {{#each blogs limit=12}}
180
+ <article class="post-card">
181
+ {{#if thumbnailImage}}
182
+ <img src="{{thumbnailImage}}" alt="{{name}}">
183
+ {{/if}}
184
+ <h2><a href="{{url}}">{{name}}</a></h2>
185
+ <p>{{postSummary}}</p>
186
+ {{#if author}}
187
+ <span>By {{author.name}}</span>
188
+ {{/if}}
189
+ </article>
190
+ {{/each}}
191
+ </div>
192
+ </main>
193
+ \`\`\`
194
+
195
+ ## Detail Template Pattern
196
+
197
+ \`\`\`html
198
+ <article class="blog-post">
199
+ {{#if mainImage}}
200
+ <img src="{{mainImage}}" alt="{{name}}">
201
+ {{/if}}
202
+
203
+ <h1>{{name}}</h1>
204
+
205
+ {{#if author}}
206
+ <div class="author">
207
+ By <a href="{{author.url}}">{{author.name}}</a>
208
+ </div>
209
+ {{/if}}
210
+
211
+ <div class="content">
212
+ {{{postBody}}}
213
+ </div>
214
+ </article>
215
+ \`\`\`
216
+
217
+ ## Static Page Pattern
218
+
219
+ \`\`\`html
220
+ <main class="about-page">
221
+ <h1 data-edit-key="about-title">About Us</h1>
222
+ <p data-edit-key="about-intro">Introduction text...</p>
223
+
224
+ <section>
225
+ <h2 data-edit-key="about-mission-title">Our Mission</h2>
226
+ <p data-edit-key="about-mission-text">Mission statement...</p>
227
+ </section>
228
+ </main>
229
+ \`\`\`
230
+
231
+ ## Template Must-Haves
232
+
233
+ ✓ Include complete header (copy from source)
234
+ ✓ Include complete footer (copy from source)
235
+ ✓ All asset paths use /public/
236
+ ✓ Rich text fields use {{{triple braces}}}`,
237
+ tokens: `# Token Reference
238
+
239
+ ## Double Braces {{...}} - Escaped Output
240
+ Use for text, URLs, images:
241
+ \`\`\`html
242
+ {{name}}
243
+ {{mainImage}}
244
+ {{url}}
245
+ {{author.name}}
246
+ \`\`\`
247
+
248
+ ## Triple Braces {{{...}}} - Raw HTML
249
+ Use for rich text content:
250
+ \`\`\`html
251
+ {{{postBody}}}
252
+ {{{bio}}}
253
+ {{{author.bio}}}
254
+ \`\`\`
255
+
256
+ **CRITICAL:** If a field contains HTML, you MUST use triple braces!
257
+
258
+ ## Loop Syntax
259
+ \`\`\`html
260
+ {{#each blogs}}
261
+ ...content for each item...
262
+ {{/each}}
263
+ \`\`\`
264
+
265
+ **Modifiers:**
266
+ - \`limit=N\` - Maximum items
267
+ - \`featured=true\` - Only featured
268
+ - \`sort="field"\` - Sort by field
269
+ - \`order="asc|desc"\` - Sort direction
270
+
271
+ ## Conditionals
272
+ \`\`\`html
273
+ {{#if fieldName}}
274
+ ...show if truthy...
275
+ {{else}}
276
+ ...show if falsy...
277
+ {{/if}}
278
+
279
+ {{#unless fieldName}}
280
+ ...show if falsy...
281
+ {{/unless}}
282
+ \`\`\`
283
+
284
+ ## Loop Variables
285
+ Inside {{#each}}:
286
+ - \`{{@first}}\` - true for first item
287
+ - \`{{@last}}\` - true for last item
288
+ - \`{{@index}}\` - zero-based index
289
+
290
+ ## Collection Fields
291
+
292
+ **Blog Posts:**
293
+ - {{name}}, {{slug}}, {{url}}
294
+ - {{mainImage}}, {{thumbnailImage}}
295
+ - {{postSummary}}, {{{postBody}}}
296
+ - {{featured}}, {{publishedAt}}
297
+ - {{author.name}}, {{author.picture}}, {{{author.bio}}}
298
+
299
+ **Authors:**
300
+ - {{name}}, {{slug}}, {{url}}
301
+ - {{picture}}, {{{bio}}}
302
+ - {{email}}, {{twitterProfileLink}}, {{linkedinProfileLink}}
303
+
304
+ **Team:**
305
+ - {{name}}, {{slug}}, {{role}}
306
+ - {{photo}}, {{{bio}}}, {{email}}
307
+ - {{order}}
308
+
309
+ **Downloads:**
310
+ - {{title}}, {{slug}}, {{description}}
311
+ - {{fileUrl}}, {{category}}, {{order}}`,
312
+ forms: `# Form Handling
313
+
314
+ Forms are automatically captured by the CMS.
315
+
316
+ ## Basic Form Setup
317
+
318
+ \`\`\`html
319
+ <form data-form-name="contact">
320
+ <input type="text" name="name" required>
321
+ <input type="email" name="email" required>
322
+ <textarea name="message" required></textarea>
323
+ <button type="submit">Send</button>
324
+ </form>
325
+ \`\`\`
326
+
327
+ ## Required Attributes
328
+
329
+ - \`data-form-name="xxx"\` on the form element
330
+ - \`name="fieldName"\` on each input
331
+
332
+ ## Form Handler Script
333
+
334
+ Add to your JavaScript:
335
+
336
+ \`\`\`javascript
337
+ document.querySelectorAll('form[data-form-name]').forEach(form => {
338
+ form.addEventListener('submit', async (e) => {
339
+ e.preventDefault();
340
+
341
+ const formData = new FormData(form);
342
+ const data = Object.fromEntries(formData);
343
+
344
+ const response = await fetch('/api/forms/submit', {
345
+ method: 'POST',
346
+ headers: { 'Content-Type': 'application/json' },
347
+ body: JSON.stringify({
348
+ formName: form.dataset.formName,
349
+ data: data
350
+ })
351
+ });
352
+
353
+ if (response.ok) {
354
+ form.reset();
355
+ alert('Thank you!');
356
+ }
357
+ });
358
+ });
359
+ \`\`\`
360
+
361
+ ## Naming Conventions
362
+
363
+ - Contact form → \`contact\`
364
+ - Newsletter → \`newsletter\`
365
+ - Quote request → \`quote-request\`
366
+ - Application → \`job-application\`
367
+
368
+ ## Important
369
+
370
+ **Tenant context is automatic** - the system handles associating forms with the correct site.`,
371
+ assets: `# Asset Path Rules
372
+
373
+ ## The Rule
374
+
375
+ **ALL asset paths must use /public/ prefix**
376
+
377
+ ## HTML Examples
378
+
379
+ \`\`\`html
380
+ <!-- CSS -->
381
+ <link rel="stylesheet" href="/public/css/style.css">
382
+
383
+ <!-- JavaScript -->
384
+ <script src="/public/js/main.js"></script>
385
+
386
+ <!-- Images -->
387
+ <img src="/public/images/logo.png" alt="Logo">
388
+
389
+ <!-- Favicon -->
390
+ <link rel="icon" href="/public/images/favicon.ico">
391
+ \`\`\`
392
+
393
+ ## CSS Examples
394
+
395
+ \`\`\`css
396
+ /* Correct */
397
+ background-image: url('/public/images/hero.jpg');
398
+ src: url('/public/fonts/custom.woff2');
399
+
400
+ /* Wrong */
401
+ background-image: url('../images/hero.jpg');
402
+ background-image: url('images/hero.jpg');
403
+ \`\`\`
404
+
405
+ ## Conversion Table
406
+
407
+ | Original | Converted |
408
+ |----------|-----------|
409
+ | css/style.css | /public/css/style.css |
410
+ | ../css/style.css | /public/css/style.css |
411
+ | ./images/logo.png | /public/images/logo.png |
412
+ | /images/logo.png | /public/images/logo.png |
413
+
414
+ ## External Assets
415
+
416
+ Keep external URLs unchanged:
417
+ \`\`\`html
418
+ <!-- These stay the same -->
419
+ <link href="https://fonts.googleapis.com/..." rel="stylesheet">
420
+ <script src="https://cdn.example.com/lib.js"></script>
421
+ \`\`\``,
422
+ checklist: `# Pre-Submission Checklist
423
+
424
+ ## ✓ Structure
425
+ - [ ] manifest.json at package root
426
+ - [ ] Static pages in pages/ folder
427
+ - [ ] Assets in public/ folder
428
+ - [ ] Templates in templates/ folder
429
+
430
+ ## ✓ manifest.json
431
+ - [ ] All static pages listed in pages array
432
+ - [ ] Each page has path, file, title
433
+ - [ ] CMS templates configured with correct paths
434
+ - [ ] Paths match original site URLs
435
+
436
+ ## ✓ Assets
437
+ - [ ] ALL CSS uses /public/ paths
438
+ - [ ] ALL JS uses /public/ paths
439
+ - [ ] ALL images use /public/ paths
440
+ - [ ] CSS background-image urls updated
441
+ - [ ] Font paths in CSS updated
442
+
443
+ ## ✓ Templates
444
+ - [ ] Templates include header/footer
445
+ - [ ] {{#each}} loops have {{/each}}
446
+ - [ ] {{#if}} conditions have {{/if}}
447
+ - [ ] Rich text uses {{{triple braces}}}
448
+ - [ ] Correct field names used
449
+
450
+ ## ✓ Field Names
451
+
452
+ **Blog Posts:**
453
+ - ✓ {{name}} NOT {{title}}
454
+ - ✓ {{mainImage}} NOT {{coverImage}}
455
+ - ✓ {{postSummary}} NOT {{excerpt}}
456
+ - ✓ {{{postBody}}} with triple braces
457
+
458
+ **Team:**
459
+ - ✓ {{photo}} NOT {{picture}}
460
+ - ✓ {{{bio}}} with triple braces
461
+
462
+ **Authors:**
463
+ - ✓ {{picture}} NOT {{photo}}
464
+ - ✓ {{{bio}}} with triple braces
465
+
466
+ ## ✓ Static Pages
467
+ - [ ] data-edit-key on editable text
468
+ - [ ] Keys are unique and descriptive
469
+ - [ ] Forms have data-form-name
470
+
471
+ ## ✓ Final Validation
472
+ - [ ] Run validate_manifest with manifest.json
473
+ - [ ] Run validate_template on each template
474
+ - [ ] Run validate_package for full check`,
475
+ full: '', // Will be assembled from all sections
476
+ };
477
+ /**
478
+ * Returns the conversion guide, either full or a specific section
479
+ */
480
+ async function getConversionGuide(section) {
481
+ if (section === 'full') {
482
+ return `# Complete Website Conversion Guide
483
+
484
+ ${SECTIONS.analysis}
485
+
486
+ ---
487
+
488
+ ${SECTIONS.structure}
489
+
490
+ ---
491
+
492
+ ${SECTIONS.manifest}
493
+
494
+ ---
495
+
496
+ ${SECTIONS.templates}
497
+
498
+ ---
499
+
500
+ ${SECTIONS.tokens}
501
+
502
+ ---
503
+
504
+ ${SECTIONS.forms}
505
+
506
+ ---
507
+
508
+ ${SECTIONS.assets}
509
+
510
+ ---
511
+
512
+ ${SECTIONS.checklist}
513
+
514
+ ---
515
+
516
+ ## Need More Help?
517
+
518
+ Use these MCP tools during conversion:
519
+
520
+ - \`get_schema\` - Get all collection fields and tokens
521
+ - \`get_example\` - Get code examples for specific patterns
522
+ - \`validate_manifest\` - Check your manifest.json
523
+ - \`validate_template\` - Check template token usage
524
+ - \`validate_package\` - Full package validation
525
+
526
+ **Validate as you work** - don't wait until the end!`;
527
+ }
528
+ return SECTIONS[section] || `Section not found: ${section}`;
529
+ }
@@ -0,0 +1,7 @@
1
+ type ExampleType = 'manifest_basic' | 'manifest_custom_paths' | 'blog_index_template' | 'blog_post_template' | 'team_template' | 'downloads_template' | 'authors_template' | 'author_detail_template' | 'custom_collection_template' | 'form_handling' | 'asset_paths' | 'data_edit_keys' | 'each_loop' | 'conditional_if' | 'nested_fields' | 'featured_posts';
2
+ /**
3
+ * Returns example code for a specific pattern
4
+ */
5
+ export declare function getExample(exampleType: ExampleType): Promise<string>;
6
+ export {};
7
+ //# sourceMappingURL=get-example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-example.d.ts","sourceRoot":"","sources":["../../src/tools/get-example.ts"],"names":[],"mappings":"AAAA,KAAK,WAAW,GACZ,gBAAgB,GAChB,uBAAuB,GACvB,qBAAqB,GACrB,oBAAoB,GACpB,eAAe,GACf,oBAAoB,GACpB,kBAAkB,GAClB,wBAAwB,GACxB,4BAA4B,GAC5B,eAAe,GACf,aAAa,GACb,gBAAgB,GAChB,WAAW,GACX,gBAAgB,GAChB,eAAe,GACf,gBAAgB,CAAC;AA0qBrB;;GAEG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1E"}