multisite-cms-mcp 1.0.20 → 1.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"get-conversion-guide.d.ts","sourceRoot":"","sources":["../../src/tools/get-conversion-guide.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AA2tB1H;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkD1E"}
1
+ {"version":3,"file":"get-conversion-guide.d.ts","sourceRoot":"","sources":["../../src/tools/get-conversion-guide.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AA4tB1H;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkD1E"}
@@ -193,34 +193,35 @@ The editor automatically detects when you're viewing a CMS path (like /blog or /
193
193
 
194
194
  ## Custom Collection Templates
195
195
 
196
- For custom collections (beyond the built-in blog, team, downloads, authors):
196
+ For custom collections (beyond the built-in blog, team, downloads, authors), use the **flat format**:
197
197
 
198
198
  \`\`\`json
199
199
  {
200
200
  "cmsTemplates": {
201
- "collectionTemplates": {
202
- "video": {
203
- "indexPath": "/videos",
204
- "detailPath": "/video",
205
- "indexTemplate": "templates/videos_index.html",
206
- "detailTemplate": "templates/video_detail.html"
207
- },
208
- "product": {
209
- "indexPath": "/shop",
210
- "detailPath": "/product",
211
- "indexTemplate": "templates/shop.html",
212
- "detailTemplate": "templates/product_detail.html"
213
- }
214
- }
201
+ // Custom collection: video
202
+ "videoIndex": "pages/videos.html",
203
+ "videoIndexPath": "/videos",
204
+ "videoDetail": "templates/video-detail.html",
205
+ "videoDetailPath": "/videos",
206
+
207
+ // Custom collection: product
208
+ "productIndex": "pages/shop.html",
209
+ "productIndexPath": "/shop",
210
+ "productDetail": "templates/product-detail.html",
211
+ "productDetailPath": "/product"
215
212
  }
216
213
  }
217
214
  \`\`\`
218
215
 
219
- **Path Configuration:**
220
- - \`indexPath\` - URL for the collection list page (e.g., /videos)
221
- - \`detailPath\` - Base URL for individual item pages (e.g., /video → /video/item-slug)
216
+ **Path Configuration (flat format):**
217
+ - \`{slug}Index\` - Template file for the index/listing page
218
+ - \`{slug}IndexPath\` - URL for the collection list page (e.g., /videos)
219
+ - \`{slug}Detail\` - Template file for the detail page
220
+ - \`{slug}DetailPath\` - Base URL for individual item pages (e.g., /videos → /videos/item-slug)
221
+
222
+ **IMPORTANT:** The collection's internal slug is for database only. URL paths come EXCLUSIVELY from the manifest.
222
223
 
223
- This allows different paths for list vs detail pages (e.g., /videos for list, /video/my-video for detail).`,
224
+ This allows same or different paths for list vs detail pages (e.g., /videos for both, or /shop for list and /product for detail).`,
224
225
  templates: `# Template Creation Guide
225
226
 
226
227
  ## Template Types
@@ -441,30 +441,30 @@ Every custom collection item automatically has:
441
441
  - \`{{url}}\` - Full URL to detail page
442
442
  - \`{{publishedAt}}\` - Publish date (REQUIRED)
443
443
 
444
- ## In manifest.json
444
+ ## In manifest.json (Flat Format)
445
445
 
446
446
  \`\`\`json
447
447
  {
448
448
  "cmsTemplates": {
449
- "collectionTemplates": {
450
- "products": {
451
- "indexPath": "/shop",
452
- "detailPath": "/product",
453
- "indexTemplate": "templates/products_index.html",
454
- "detailTemplate": "templates/product_detail.html"
455
- }
456
- }
449
+ "productIndex": "pages/shop.html",
450
+ "productIndexPath": "/shop",
451
+ "productDetail": "templates/product-detail.html",
452
+ "productDetailPath": "/product"
457
453
  }
458
454
  }
459
455
  \`\`\`
460
456
 
461
- **Path Configuration:**
462
- - \`indexPath\` - URL for the list page (e.g., /shop → lists all products)
463
- - \`detailPath\` - Base URL for detail pages (e.g., /product/product/my-product-slug)
457
+ **Path Configuration (flat format):**
458
+ - \`{slug}Index\` - Template file for the list page
459
+ - \`{slug}IndexPath\` - URL for the list page (e.g., /shoplists all products)
460
+ - \`{slug}Detail\` - Template file for the detail page
461
+ - \`{slug}DetailPath\` - Base URL for detail pages (e.g., /product → /product/my-product-slug)
464
462
 
465
463
  This serves:
466
- - Collection index at \`/shop\` (lists all products)
467
- - Detail pages at \`/product/product-slug\` (individual product)`,
464
+ - Collection index at \`/shop\` (lists all products using productIndex template)
465
+ - Detail pages at \`/product/product-slug\` (individual product using productDetail template)
466
+
467
+ **IMPORTANT:** The manifest's paths are the SINGLE SOURCE OF TRUTH. Collection slug is for database only.`,
468
468
  form_handling: `# Form Handling
469
469
 
470
470
  Forms are automatically captured by the CMS:
@@ -1 +1 @@
1
- {"version":3,"file":"get-schema.d.ts","sourceRoot":"","sources":["../../src/tools/get-schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAuZjD"}
1
+ {"version":3,"file":"get-schema.d.ts","sourceRoot":"","sources":["../../src/tools/get-schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CA4ajD"}
@@ -325,39 +325,60 @@ For HTML content that should NOT be escaped:
325
325
 
326
326
  ## CMS Template Configuration
327
327
 
328
- Templates can be configured two ways:
328
+ Templates are configured in manifest.json using a **flat format** that is the SINGLE SOURCE OF TRUTH for URL paths.
329
329
 
330
- ### 1. In manifest.json
330
+ ### manifest.json Format
331
331
  \`\`\`json
332
332
  {
333
333
  "cmsTemplates": {
334
- "blogIndex": "templates/blog_index.html",
334
+ // Built-in: Blog
335
+ "blogIndex": "pages/blog.html",
335
336
  "blogIndexPath": "/blog",
336
- "blogPost": "templates/blog_post.html",
337
+ "blogPost": "templates/blog-post.html",
337
338
  "blogPostPath": "/blog",
338
- "team": "templates/team.html",
339
+
340
+ // Built-in: Team, Downloads, Authors
341
+ "team": "pages/team.html",
339
342
  "teamPath": "/team",
340
- "downloads": "templates/downloads.html",
341
- "downloadsPath": "/resources"
343
+ "downloads": "pages/downloads.html",
344
+ "downloadsPath": "/resources",
345
+ "authorsIndex": "pages/authors.html",
346
+ "authorsIndexPath": "/authors",
347
+
348
+ // Custom Collections: Use {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
349
+ "videoIndex": "pages/videos.html",
350
+ "videoIndexPath": "/videos",
351
+ "videoDetail": "templates/video-detail.html",
352
+ "videoDetailPath": "/videos",
353
+
354
+ "serviceIndex": "pages/services.html",
355
+ "serviceIndexPath": "/services",
356
+ "serviceDetail": "templates/service-detail.html",
357
+ "serviceDetailPath": "/service"
342
358
  }
343
359
  }
344
360
  \`\`\`
345
361
 
346
- ### 2. Via Settings UI (after upload)
347
- Go to **Dashboard → Settings → CMS Templates** to:
348
- - Select which uploaded page serves as each template type
349
- - Configure custom URL paths for each CMS section
350
- - Changes take effect immediately
351
-
352
- **Template Types:**
353
- - **Blog Index** - Lists all blog posts (e.g., /blog)
354
- - **Blog Post** - Single blog post detail page (e.g., /blog/my-post)
355
- - **Team** - Team members page (e.g., /team)
356
- - **Downloads** - Downloadable files listing (e.g., /resources)
357
- - **Authors Index** - Lists all authors
358
- - **Author Detail** - Single author profile page
359
-
360
- **Note:** The editor shows a warning banner when viewing CMS paths (like /blog) that don't have templates configured.
362
+ ### Custom Collection URL Routing
363
+
364
+ **IMPORTANT:** The collection's internal slug (set in CMS) is for database only, NOT for URLs.
365
+ URL paths come EXCLUSIVELY from the manifest's \`{slug}IndexPath\` and \`{slug}DetailPath\`.
366
+
367
+ **Example:** Collection with slug \`video\` but paths \`/videos\` and \`/videos/:itemSlug\`:
368
+ - \`videoIndexPath: "/videos"\` → Index page at \`/videos\`
369
+ - \`videoDetailPath: "/videos"\` Detail pages at \`/videos/my-video\`
370
+
371
+ **Different paths for index and detail:**
372
+ - \`serviceIndexPath: "/services"\` Index at \`/services\`
373
+ - \`serviceDetailPath: "/service"\` Detail at \`/service/my-service\`
374
+
375
+ ### Template Types
376
+ - **{slug}Index** - Template file for the index/listing page
377
+ - **{slug}IndexPath** - URL path for the index page
378
+ - **{slug}Detail** - Template file for the detail page
379
+ - **{slug}DetailPath** - URL path base for detail pages (item slug appended)
380
+
381
+ **Note:** The CMS settings UI can also configure these, but manifest.json takes precedence for AI conversions.
361
382
 
362
383
  ---
363
384
 
@@ -1 +1 @@
1
- {"version":3,"file":"validate-manifest.d.ts","sourceRoot":"","sources":["../../src/tools/validate-manifest.ts"],"names":[],"mappings":"AA8BA;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsI5E"}
1
+ {"version":3,"file":"validate-manifest.d.ts","sourceRoot":"","sources":["../../src/tools/validate-manifest.ts"],"names":[],"mappings":"AAyCA;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4N5E"}
@@ -8,7 +8,8 @@ const pageSchema = zod_1.z.object({
8
8
  title: zod_1.z.string(),
9
9
  editable: zod_1.z.boolean().optional(),
10
10
  });
11
- const cmsTemplatesSchema = zod_1.z.object({
11
+ // Built-in collection templates
12
+ const builtInTemplatesSchema = zod_1.z.object({
12
13
  blogIndex: zod_1.z.string().optional(),
13
14
  blogIndexPath: zod_1.z.string().startsWith('/').optional(),
14
15
  blogPost: zod_1.z.string().optional(),
@@ -20,8 +21,17 @@ const cmsTemplatesSchema = zod_1.z.object({
20
21
  authorsIndex: zod_1.z.string().optional(),
21
22
  authorDetail: zod_1.z.string().optional(),
22
23
  authorsIndexPath: zod_1.z.string().startsWith('/').optional(),
24
+ // Legacy format - deprecated
23
25
  collectionPaths: zod_1.z.record(zod_1.z.string().startsWith('/')).optional(),
24
- }).optional();
26
+ collectionTemplates: zod_1.z.record(zod_1.z.object({
27
+ path: zod_1.z.string().startsWith('/').optional(),
28
+ indexTemplate: zod_1.z.string().optional(),
29
+ detailTemplate: zod_1.z.string().optional(),
30
+ })).optional(),
31
+ });
32
+ // Custom collection templates use flat format: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
33
+ // This schema allows any additional string keys for custom collections
34
+ const cmsTemplatesSchema = builtInTemplatesSchema.catchall(zod_1.z.string()).optional();
25
35
  const manifestSchema = zod_1.z.object({
26
36
  pages: zod_1.z.array(pageSchema),
27
37
  cmsTemplates: cmsTemplatesSchema,
@@ -85,6 +95,7 @@ The manifest.json file is not valid JSON. Check for:
85
95
  }
86
96
  // Check cmsTemplates
87
97
  const templates = m.cmsTemplates;
98
+ const customCollections = new Set();
88
99
  if (templates) {
89
100
  // Check template file paths
90
101
  const templateFields = ['blogIndex', 'blogPost', 'team', 'downloads', 'authorsIndex', 'authorDetail'];
@@ -120,9 +131,85 @@ The manifest.json file is not valid JSON. Check for:
120
131
  if (templates.authorDetail && !templates.authorsIndex) {
121
132
  warnings.push('- authorDetail template defined but no authorsIndex - authors need both templates');
122
133
  }
134
+ // Detect and validate custom collection templates (flat format)
135
+ // Pattern: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
136
+ const allKeys = Object.keys(templates);
137
+ for (const key of allKeys) {
138
+ // Skip built-in keys
139
+ if (['blogIndex', 'blogIndexPath', 'blogPost', 'blogPostPath', 'team', 'teamPath',
140
+ 'downloads', 'downloadsPath', 'authorsIndex', 'authorDetail', 'authorsIndexPath',
141
+ 'collectionPaths', 'collectionTemplates'].includes(key)) {
142
+ continue;
143
+ }
144
+ // Extract collection slug from key pattern
145
+ let slug = null;
146
+ if (key.endsWith('Index') && !key.endsWith('IndexPath')) {
147
+ slug = key.slice(0, -5); // Remove 'Index'
148
+ }
149
+ else if (key.endsWith('Detail') && !key.endsWith('DetailPath')) {
150
+ slug = key.slice(0, -6); // Remove 'Detail'
151
+ }
152
+ else if (key.endsWith('IndexPath')) {
153
+ slug = key.slice(0, -9); // Remove 'IndexPath'
154
+ }
155
+ else if (key.endsWith('DetailPath')) {
156
+ slug = key.slice(0, -10); // Remove 'DetailPath'
157
+ }
158
+ if (slug && slug.length > 0) {
159
+ customCollections.add(slug);
160
+ }
161
+ }
162
+ // Validate each custom collection
163
+ for (const slug of customCollections) {
164
+ const indexTemplate = templates[`${slug}Index`];
165
+ const detailTemplate = templates[`${slug}Detail`];
166
+ const indexPath = templates[`${slug}IndexPath`];
167
+ const detailPath = templates[`${slug}DetailPath`];
168
+ // Check template file paths
169
+ if (typeof indexTemplate === 'string') {
170
+ if (!indexTemplate.endsWith('.html')) {
171
+ warnings.push(`- cmsTemplates.${slug}Index: should end with .html (got: ${indexTemplate})`);
172
+ }
173
+ }
174
+ if (typeof detailTemplate === 'string') {
175
+ if (!detailTemplate.endsWith('.html')) {
176
+ warnings.push(`- cmsTemplates.${slug}Detail: should end with .html (got: ${detailTemplate})`);
177
+ }
178
+ }
179
+ // Check path format
180
+ if (typeof indexPath === 'string' && !indexPath.startsWith('/')) {
181
+ errors.push(`- cmsTemplates.${slug}IndexPath: must start with "/" (got: ${indexPath})`);
182
+ }
183
+ if (typeof detailPath === 'string' && !detailPath.startsWith('/')) {
184
+ errors.push(`- cmsTemplates.${slug}DetailPath: must start with "/" (got: ${detailPath})`);
185
+ }
186
+ // Check consistency - if you have one, you should have the others
187
+ if (indexTemplate && !indexPath) {
188
+ warnings.push(`- Custom collection "${slug}": has ${slug}Index but no ${slug}IndexPath`);
189
+ }
190
+ if (detailTemplate && !detailPath) {
191
+ warnings.push(`- Custom collection "${slug}": has ${slug}Detail but no ${slug}DetailPath`);
192
+ }
193
+ if (indexPath && !indexTemplate) {
194
+ warnings.push(`- Custom collection "${slug}": has ${slug}IndexPath but no ${slug}Index template`);
195
+ }
196
+ if (detailPath && !detailTemplate) {
197
+ warnings.push(`- Custom collection "${slug}": has ${slug}DetailPath but no ${slug}Detail template`);
198
+ }
199
+ // Note: indexPath and detailPath can be the same (e.g., both "/videos")
200
+ // The system distinguishes by whether a slug segment exists after the path
201
+ }
202
+ // Warn about deprecated collectionTemplates format
203
+ if (templates.collectionTemplates) {
204
+ warnings.push('- cmsTemplates.collectionTemplates: This nested format is deprecated. Use flat format instead: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath');
205
+ }
123
206
  }
124
207
  // Build result
125
208
  let output = '';
209
+ // Build custom collections summary
210
+ const customCollectionsSummary = customCollections.size > 0
211
+ ? `\n- Custom collections: ${Array.from(customCollections).join(', ')} (using flat format: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath)`
212
+ : '';
126
213
  if (errors.length === 0 && warnings.length === 0) {
127
214
  output = `✅ MANIFEST VALID
128
215
 
@@ -130,7 +217,7 @@ The manifest.json structure is correct.
130
217
 
131
218
  Summary:
132
219
  - ${m.pages?.length || 0} static page(s) defined
133
- - CMS templates: ${templates ? 'configured in manifest' : 'not configured (can be set via Settings → CMS Templates after upload)'}
220
+ - CMS templates: ${templates ? 'configured in manifest' : 'not configured (can be set via Settings → CMS Templates after upload)'}${customCollectionsSummary}
134
221
  - Head HTML: ${m.defaultHeadHtml ? 'configured' : 'not configured'}`;
135
222
  }
136
223
  else if (errors.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multisite-cms-mcp",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "MCP server for AI-assisted website conversion to CMS format. Provides validation, examples, and schema tools.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {