payload-mcp-toolkit 0.2.0 → 0.3.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.
- package/README.md +59 -42
- package/dist/__tests__/introspection.test.js +141 -46
- package/dist/__tests__/introspection.test.js.map +1 -1
- package/dist/draft-workflow.d.ts +24 -19
- package/dist/draft-workflow.js +78 -31
- package/dist/draft-workflow.js.map +1 -1
- package/dist/index.d.ts +10 -15
- package/dist/index.js +43 -70
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts +14 -7
- package/dist/introspection.js +92 -68
- package/dist/introspection.js.map +1 -1
- package/dist/prompts.d.ts +4 -4
- package/dist/prompts.js +44 -35
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +9 -4
- package/dist/resources.js +44 -52
- package/dist/resources.js.map +1 -1
- package/dist/tools/patch-layout.d.ts +15 -79
- package/dist/tools/patch-layout.js +140 -48
- package/dist/tools/patch-layout.js.map +1 -1
- package/dist/types.d.ts +82 -53
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/compose-helpers.d.ts +0 -117
- package/dist/tools/compose-helpers.js +0 -236
- package/dist/tools/compose-helpers.js.map +0 -1
- package/dist/tools/compose-layout.d.ts +0 -139
- package/dist/tools/compose-layout.js +0 -61
- package/dist/tools/compose-layout.js.map +0 -1
package/dist/introspection.js
CHANGED
|
@@ -32,55 +32,47 @@
|
|
|
32
32
|
return map;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const sections = sectionBlocks.map((section)=>{
|
|
44
|
-
const blockFields = findBlockFields(section.fields);
|
|
45
|
-
if (blockFields.length === 0) {
|
|
46
|
-
// Fixed section — no nested blocks
|
|
47
|
-
return {
|
|
48
|
-
slug: section.slug,
|
|
49
|
-
nestingType: 'fixed',
|
|
50
|
-
acceptedLeafSlugs: [],
|
|
51
|
-
fields: extractFields(section.fields)
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// Determine accepted leaf slugs from all blocks-type fields
|
|
55
|
-
const acceptedSlugs = new Set();
|
|
56
|
-
let maxRows;
|
|
57
|
-
for (const bf of blockFields){
|
|
58
|
-
const slugs = getBlockSlugsFromField(bf);
|
|
59
|
-
for (const s of slugs){
|
|
60
|
-
if (leafSlugs.has(s)) acceptedSlugs.add(s);
|
|
61
|
-
}
|
|
62
|
-
if (bf.maxRows) maxRows = bf.maxRows;
|
|
63
|
-
}
|
|
64
|
-
const nestingType = acceptedSlugs.size < leafSlugs.size || maxRows ? 'constrained' : 'composable';
|
|
65
|
-
return {
|
|
66
|
-
slug: section.slug,
|
|
67
|
-
nestingType,
|
|
68
|
-
acceptedLeafSlugs: [
|
|
69
|
-
...acceptedSlugs
|
|
70
|
-
],
|
|
71
|
-
maxRows,
|
|
72
|
-
fields: extractFields(section.fields)
|
|
73
|
-
};
|
|
74
|
-
});
|
|
75
|
-
const leaves = leafBlocks.map((leaf)=>({
|
|
76
|
-
slug: leaf.slug,
|
|
77
|
-
fields: extractFields(leaf.fields)
|
|
35
|
+
* Build a flat catalog of every block in the schema. Whether a block can
|
|
36
|
+
* nest other blocks is represented separately in the BlockNestingMap, not
|
|
37
|
+
* as a section/leaf classification — the AI reads both and composes
|
|
38
|
+
* arbitrarily-nested layouts from there.
|
|
39
|
+
*/ export function introspectBlocks(blocks) {
|
|
40
|
+
const catalog = blocks.map((block)=>({
|
|
41
|
+
slug: block.slug,
|
|
42
|
+
fields: extractFields(block.fields)
|
|
78
43
|
}));
|
|
79
44
|
return {
|
|
80
|
-
|
|
81
|
-
leaves
|
|
45
|
+
blocks: catalog
|
|
82
46
|
};
|
|
83
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Walk every collection and every block, recording each `blocks`-typed
|
|
50
|
+
* field's owner, dotted path, and accepted slugs.
|
|
51
|
+
*
|
|
52
|
+
* The AI uses this to compose layouts at any depth: it looks up which
|
|
53
|
+
* slugs the relevant field accepts, picks one, then if that block has
|
|
54
|
+
* its own `blocks` fields it recurses against the same map.
|
|
55
|
+
*/ export function buildBlockNestingMap(collections, blocks) {
|
|
56
|
+
const knownSlugs = new Set(blocks.map((b)=>b.slug));
|
|
57
|
+
const edges = [];
|
|
58
|
+
for (const collection of collections){
|
|
59
|
+
edges.push(...collectBlocksFieldEdges(collection.fields, {
|
|
60
|
+
owner: collection.slug,
|
|
61
|
+
ownerType: 'collection',
|
|
62
|
+
prefix: '',
|
|
63
|
+
knownSlugs
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
for (const block of blocks){
|
|
67
|
+
edges.push(...collectBlocksFieldEdges(block.fields, {
|
|
68
|
+
owner: block.slug,
|
|
69
|
+
ownerType: 'block',
|
|
70
|
+
prefix: '',
|
|
71
|
+
knownSlugs
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
return edges;
|
|
75
|
+
}
|
|
84
76
|
/**
|
|
85
77
|
* Build a relationship graph from introspected collection schemas.
|
|
86
78
|
*/ export function buildRelationshipGraph(schemas) {
|
|
@@ -111,9 +103,10 @@
|
|
|
111
103
|
};
|
|
112
104
|
if ('required' in field && field.required) schema.required = true;
|
|
113
105
|
if ('hasMany' in field && field.hasMany) schema.hasMany = true;
|
|
114
|
-
if ('relationTo' in field && field.relationTo)
|
|
106
|
+
if ('relationTo' in field && field.relationTo) {
|
|
107
|
+
schema.relationTo = field.relationTo;
|
|
108
|
+
}
|
|
115
109
|
if ('maxRows' in field && field.maxRows) schema.maxRows = field.maxRows;
|
|
116
|
-
// Extract select options
|
|
117
110
|
if (field.type === 'select' && 'options' in field && Array.isArray(field.options)) {
|
|
118
111
|
schema.options = field.options.map((opt)=>typeof opt === 'string' ? {
|
|
119
112
|
label: opt,
|
|
@@ -123,7 +116,6 @@
|
|
|
123
116
|
value: String(opt.value)
|
|
124
117
|
});
|
|
125
118
|
}
|
|
126
|
-
// Recurse into nested fields (arrays, groups)
|
|
127
119
|
if (field.type === 'array' && 'fields' in field) {
|
|
128
120
|
schema.fields = extractFields(field.fields);
|
|
129
121
|
}
|
|
@@ -132,7 +124,6 @@
|
|
|
132
124
|
}
|
|
133
125
|
result.push(schema);
|
|
134
126
|
}
|
|
135
|
-
// Transparent containers — recurse without creating a named field
|
|
136
127
|
if (field.type === 'tabs' && 'tabs' in field) {
|
|
137
128
|
for (const tab of field.tabs){
|
|
138
129
|
if ('fields' in tab) {
|
|
@@ -169,7 +160,6 @@
|
|
|
169
160
|
hasMany: !!('hasMany' in field && field.hasMany)
|
|
170
161
|
});
|
|
171
162
|
}
|
|
172
|
-
// Recurse into containers
|
|
173
163
|
if (field.type === 'tabs' && 'tabs' in field) {
|
|
174
164
|
for (const tab of field.tabs){
|
|
175
165
|
if ('fields' in tab) {
|
|
@@ -193,42 +183,76 @@
|
|
|
193
183
|
return rels;
|
|
194
184
|
}
|
|
195
185
|
/**
|
|
196
|
-
*
|
|
197
|
-
|
|
198
|
-
|
|
186
|
+
* Walk fields recording every `blocks`-typed field encountered, including
|
|
187
|
+
* those nested in tabs/rows/groups/arrays/collapsibles. Each entry carries
|
|
188
|
+
* the dotted path from the owner root to the field.
|
|
189
|
+
*/ function collectBlocksFieldEdges(fields, ctx) {
|
|
190
|
+
const edges = [];
|
|
199
191
|
for (const field of fields){
|
|
200
192
|
if (field.type === 'blocks') {
|
|
201
|
-
|
|
193
|
+
const fieldName = 'name' in field && field.name ? field.name : '';
|
|
194
|
+
const fullPath = ctx.prefix ? `${ctx.prefix}.${fieldName}` : fieldName;
|
|
195
|
+
const allSlugs = readBlockSlugs(field);
|
|
196
|
+
const acceptedSlugs = allSlugs.filter((s)=>ctx.knownSlugs.has(s));
|
|
197
|
+
const edge = {
|
|
198
|
+
owner: ctx.owner,
|
|
199
|
+
ownerType: ctx.ownerType,
|
|
200
|
+
fieldPath: fullPath,
|
|
201
|
+
acceptedBlockSlugs: acceptedSlugs
|
|
202
|
+
};
|
|
203
|
+
const maxRows = field.maxRows;
|
|
204
|
+
if (typeof maxRows === 'number') edge.maxRows = maxRows;
|
|
205
|
+
edges.push(edge);
|
|
206
|
+
continue;
|
|
202
207
|
}
|
|
203
208
|
if (field.type === 'tabs' && 'tabs' in field) {
|
|
204
209
|
for (const tab of field.tabs){
|
|
205
|
-
if ('fields' in tab)
|
|
206
|
-
|
|
207
|
-
}
|
|
210
|
+
if (!('fields' in tab)) continue;
|
|
211
|
+
const tabName = 'name' in tab && tab.name ? tab.name : '';
|
|
212
|
+
const tabPrefix = tabName ? ctx.prefix ? `${ctx.prefix}.${tabName}` : tabName : ctx.prefix;
|
|
213
|
+
edges.push(...collectBlocksFieldEdges(tab.fields, {
|
|
214
|
+
...ctx,
|
|
215
|
+
prefix: tabPrefix
|
|
216
|
+
}));
|
|
208
217
|
}
|
|
218
|
+
continue;
|
|
209
219
|
}
|
|
210
220
|
if (field.type === 'row' && 'fields' in field) {
|
|
211
|
-
|
|
221
|
+
edges.push(...collectBlocksFieldEdges(field.fields, ctx));
|
|
222
|
+
continue;
|
|
212
223
|
}
|
|
213
224
|
if (field.type === 'collapsible' && 'fields' in field) {
|
|
214
|
-
|
|
225
|
+
edges.push(...collectBlocksFieldEdges(field.fields, ctx));
|
|
226
|
+
continue;
|
|
215
227
|
}
|
|
216
|
-
if (field.type === 'group' && 'fields' in field) {
|
|
217
|
-
|
|
228
|
+
if (field.type === 'group' && 'fields' in field && 'name' in field && field.name) {
|
|
229
|
+
const newPrefix = ctx.prefix ? `${ctx.prefix}.${field.name}` : field.name;
|
|
230
|
+
edges.push(...collectBlocksFieldEdges(field.fields, {
|
|
231
|
+
...ctx,
|
|
232
|
+
prefix: newPrefix
|
|
233
|
+
}));
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (field.type === 'array' && 'fields' in field && 'name' in field && field.name) {
|
|
237
|
+
const newPrefix = ctx.prefix ? `${ctx.prefix}.${field.name}[]` : `${field.name}[]`;
|
|
238
|
+
edges.push(...collectBlocksFieldEdges(field.fields, {
|
|
239
|
+
...ctx,
|
|
240
|
+
prefix: newPrefix
|
|
241
|
+
}));
|
|
242
|
+
continue;
|
|
218
243
|
}
|
|
219
244
|
}
|
|
220
|
-
return
|
|
245
|
+
return edges;
|
|
221
246
|
}
|
|
222
247
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
|
|
248
|
+
* Read block slugs from a blocks-typed field, handling both resolved
|
|
249
|
+
* (field.blocks contains objects) and unresolved (field.blockReferences
|
|
250
|
+
* holds slug strings) forms.
|
|
251
|
+
*/ function readBlockSlugs(field) {
|
|
226
252
|
const f = field;
|
|
227
|
-
|
|
228
|
-
if (Array.isArray(f.blocks) && f.blocks.length > 0 && typeof f.blocks[0] === 'object' && f.blocks[0].slug) {
|
|
253
|
+
if (Array.isArray(f.blocks) && f.blocks.length > 0 && typeof f.blocks[0] === 'object' && f.blocks[0]?.slug) {
|
|
229
254
|
return f.blocks.map((b)=>b.slug);
|
|
230
255
|
}
|
|
231
|
-
// Unresolved — blockReferences contains slug strings
|
|
232
256
|
if (Array.isArray(f.blockReferences) && f.blockReferences.length > 0) {
|
|
233
257
|
return f.blockReferences.filter((ref)=>typeof ref === 'string');
|
|
234
258
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/introspection.ts"],"sourcesContent":["import type { Block, CollectionConfig, Field, GlobalConfig } from 'payload'\nimport type {\n BlockCatalog,\n BlockNestingType,\n CollectionSchema,\n FieldSchema,\n LeafBlockSchema,\n RelationshipEdge,\n SectionBlockSchema,\n} from './types'\n\n/**\n * Introspect a Payload collection config into structured metadata.\n */\nexport function introspectCollection(collection: CollectionConfig): CollectionSchema {\n const fields = extractFields(collection.fields)\n const relationships = extractRelationships(collection.fields)\n const searchableFields = fields\n .filter((f) => ['text', 'email'].includes(f.type) && ['name', 'title', 'slug'].includes(f.name))\n .map((f) => f.name)\n\n const hasDrafts = !!(collection.versions && typeof collection.versions === 'object' && 'drafts' in collection.versions && collection.versions.drafts)\n const hasLivePreview = !!(collection.admin && typeof collection.admin === 'object' && 'livePreview' in collection.admin && collection.admin.livePreview)\n\n return {\n slug: collection.slug,\n fields,\n hasDrafts,\n hasLivePreview,\n relationships,\n searchableFields,\n }\n}\n\n/**\n * Introspect all collections into a map keyed by slug.\n */\nexport function introspectCollections(\n collections: CollectionConfig[],\n): Map<string, CollectionSchema> {\n const map = new Map<string, CollectionSchema>()\n for (const collection of collections) {\n map.set(collection.slug, introspectCollection(collection))\n }\n return map\n}\n\n/**\n * Introspect block configs into a block catalog with section/leaf hierarchy and nesting rules.\n *\n * NOTE: In the Payload plugin context, blockReferences may or may not be resolved\n * depending on when introspection runs. This function handles both cases:\n * - If field.blocks contains resolved block objects, reads slugs from them\n * - If field.blocks is empty and field.blockReferences exists, uses those slugs directly\n */\nexport function introspectBlocks(\n sectionBlocks: Block[],\n leafBlocks: Block[],\n): BlockCatalog {\n const leafSlugs = new Set(leafBlocks.map((b) => b.slug))\n\n const sections: SectionBlockSchema[] = sectionBlocks.map((section) => {\n const blockFields = findBlockFields(section.fields)\n\n if (blockFields.length === 0) {\n // Fixed section — no nested blocks\n return {\n slug: section.slug,\n nestingType: 'fixed' as BlockNestingType,\n acceptedLeafSlugs: [],\n fields: extractFields(section.fields),\n }\n }\n\n // Determine accepted leaf slugs from all blocks-type fields\n const acceptedSlugs = new Set<string>()\n let maxRows: number | undefined\n\n for (const bf of blockFields) {\n const slugs = getBlockSlugsFromField(bf)\n for (const s of slugs) {\n if (leafSlugs.has(s)) acceptedSlugs.add(s)\n }\n if (bf.maxRows) maxRows = bf.maxRows\n }\n\n const nestingType: BlockNestingType =\n acceptedSlugs.size < leafSlugs.size || maxRows ? 'constrained' : 'composable'\n\n return {\n slug: section.slug,\n nestingType,\n acceptedLeafSlugs: [...acceptedSlugs],\n maxRows,\n fields: extractFields(section.fields),\n }\n })\n\n const leaves: LeafBlockSchema[] = leafBlocks.map((leaf) => ({\n slug: leaf.slug,\n fields: extractFields(leaf.fields),\n }))\n\n return { sections, leaves }\n}\n\n/**\n * Build a relationship graph from introspected collection schemas.\n */\nexport function buildRelationshipGraph(\n schemas: Map<string, CollectionSchema>,\n): RelationshipEdge[] {\n const edges: RelationshipEdge[] = []\n for (const [slug, schema] of schemas) {\n for (const rel of schema.relationships) {\n edges.push({\n fromCollection: slug,\n fieldName: rel.fieldName,\n toCollection: rel.relationTo,\n hasMany: rel.hasMany,\n })\n }\n }\n return edges\n}\n\n// ─── Internal helpers ──────────────────────────────────────────────\n\n/**\n * Recursively extract field metadata from a Payload fields array.\n * Handles tabs, groups, arrays, rows, and collapsible containers.\n */\nfunction extractFields(fields: Field[]): FieldSchema[] {\n const result: FieldSchema[] = []\n\n for (const field of fields) {\n if ('name' in field && field.name) {\n const schema: FieldSchema = {\n name: field.name,\n type: field.type,\n }\n\n if ('required' in field && field.required) schema.required = true\n if ('hasMany' in field && field.hasMany) schema.hasMany = true\n if ('relationTo' in field && field.relationTo) schema.relationTo = field.relationTo as string | string[]\n if ('maxRows' in field && field.maxRows) schema.maxRows = field.maxRows\n\n // Extract select options\n if (field.type === 'select' && 'options' in field && Array.isArray(field.options)) {\n schema.options = field.options.map((opt) =>\n typeof opt === 'string' ? { label: opt, value: opt } : { label: String(opt.label), value: String(opt.value) },\n )\n }\n\n // Recurse into nested fields (arrays, groups)\n if (field.type === 'array' && 'fields' in field) {\n schema.fields = extractFields(field.fields)\n }\n if (field.type === 'group' && 'fields' in field) {\n schema.fields = extractFields(field.fields)\n }\n\n result.push(schema)\n }\n\n // Transparent containers — recurse without creating a named field\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if ('fields' in tab) {\n result.push(...extractFields(tab.fields))\n }\n }\n }\n if (field.type === 'row' && 'fields' in field) {\n result.push(...extractFields(field.fields))\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n result.push(...extractFields(field.fields))\n }\n }\n\n return result\n}\n\n/**\n * Extract relationship metadata from fields (for the relationship graph).\n */\nfunction extractRelationships(\n fields: Field[],\n prefix = '',\n): Array<{ fieldName: string; relationTo: string | string[]; hasMany: boolean }> {\n const rels: Array<{ fieldName: string; relationTo: string | string[]; hasMany: boolean }> = []\n\n for (const field of fields) {\n const fieldName = 'name' in field && field.name ? `${prefix}${field.name}` : prefix\n\n if (field.type === 'relationship' && 'relationTo' in field) {\n rels.push({\n fieldName,\n relationTo: field.relationTo as string | string[],\n hasMany: !!('hasMany' in field && field.hasMany),\n })\n }\n\n if (field.type === 'upload' && 'relationTo' in field) {\n rels.push({\n fieldName,\n relationTo: field.relationTo as string,\n hasMany: !!('hasMany' in field && field.hasMany),\n })\n }\n\n // Recurse into containers\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if ('fields' in tab) {\n rels.push(...extractRelationships(tab.fields, prefix))\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, `${fieldName}.`))\n }\n if (field.type === 'array' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, `${fieldName}[].`))\n }\n if (field.type === 'row' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, prefix))\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, prefix))\n }\n }\n\n return rels\n}\n\n/**\n * Find all blocks-type fields within a field array (recursing into tabs/rows/etc).\n */\nfunction findBlockFields(fields: Field[]): Array<Field & { type: 'blocks' }> {\n const result: Array<Field & { type: 'blocks' }> = []\n\n for (const field of fields) {\n if (field.type === 'blocks') {\n result.push(field as Field & { type: 'blocks' })\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if ('fields' in tab) {\n result.push(...findBlockFields(tab.fields))\n }\n }\n }\n if (field.type === 'row' && 'fields' in field) {\n result.push(...findBlockFields(field.fields))\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n result.push(...findBlockFields(field.fields))\n }\n if (field.type === 'group' && 'fields' in field) {\n result.push(...findBlockFields(field.fields))\n }\n }\n\n return result\n}\n\n/**\n * Get block slugs from a blocks-type field.\n * Handles both resolved blocks (field.blocks has objects) and unresolved blockReferences.\n */\nfunction getBlockSlugsFromField(field: Field & { type: 'blocks' }): string[] {\n const f = field as any\n\n // Resolved blocks — field.blocks contains full block objects\n if (Array.isArray(f.blocks) && f.blocks.length > 0 && typeof f.blocks[0] === 'object' && f.blocks[0].slug) {\n return f.blocks.map((b: { slug: string }) => b.slug)\n }\n\n // Unresolved — blockReferences contains slug strings\n if (Array.isArray(f.blockReferences) && f.blockReferences.length > 0) {\n return f.blockReferences.filter((ref: unknown) => typeof ref === 'string') as string[]\n }\n\n return []\n}\n"],"names":["introspectCollection","collection","fields","extractFields","relationships","extractRelationships","searchableFields","filter","f","includes","type","name","map","hasDrafts","versions","drafts","hasLivePreview","admin","livePreview","slug","introspectCollections","collections","Map","set","introspectBlocks","sectionBlocks","leafBlocks","leafSlugs","Set","b","sections","section","blockFields","findBlockFields","length","nestingType","acceptedLeafSlugs","acceptedSlugs","maxRows","bf","slugs","getBlockSlugsFromField","s","has","add","size","leaves","leaf","buildRelationshipGraph","schemas","edges","schema","rel","push","fromCollection","fieldName","toCollection","relationTo","hasMany","result","field","required","Array","isArray","options","opt","label","value","String","tab","tabs","prefix","rels","blocks","blockReferences","ref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/introspection.ts"],"sourcesContent":["import type { Block, CollectionConfig, Field } from 'payload'\nimport type {\n BlockCatalog,\n BlockNestingMap,\n BlockSchema,\n CollectionSchema,\n FieldSchema,\n RelationshipEdge,\n} from './types'\n\n/**\n * Introspect a Payload collection config into structured metadata.\n */\nexport function introspectCollection(collection: CollectionConfig): CollectionSchema {\n const fields = extractFields(collection.fields)\n const relationships = extractRelationships(collection.fields)\n const searchableFields = fields\n .filter((f) => ['text', 'email'].includes(f.type) && ['name', 'title', 'slug'].includes(f.name))\n .map((f) => f.name)\n\n const hasDrafts = !!(\n collection.versions &&\n typeof collection.versions === 'object' &&\n 'drafts' in collection.versions &&\n collection.versions.drafts\n )\n const hasLivePreview = !!(\n collection.admin &&\n typeof collection.admin === 'object' &&\n 'livePreview' in collection.admin &&\n collection.admin.livePreview\n )\n\n return {\n slug: collection.slug,\n fields,\n hasDrafts,\n hasLivePreview,\n relationships,\n searchableFields,\n }\n}\n\n/**\n * Introspect all collections into a map keyed by slug.\n */\nexport function introspectCollections(\n collections: CollectionConfig[],\n): Map<string, CollectionSchema> {\n const map = new Map<string, CollectionSchema>()\n for (const collection of collections) {\n map.set(collection.slug, introspectCollection(collection))\n }\n return map\n}\n\n/**\n * Build a flat catalog of every block in the schema. Whether a block can\n * nest other blocks is represented separately in the BlockNestingMap, not\n * as a section/leaf classification — the AI reads both and composes\n * arbitrarily-nested layouts from there.\n */\nexport function introspectBlocks(blocks: Block[]): BlockCatalog {\n const catalog: BlockSchema[] = blocks.map((block) => ({\n slug: block.slug,\n fields: extractFields(block.fields),\n }))\n return { blocks: catalog }\n}\n\n/**\n * Walk every collection and every block, recording each `blocks`-typed\n * field's owner, dotted path, and accepted slugs.\n *\n * The AI uses this to compose layouts at any depth: it looks up which\n * slugs the relevant field accepts, picks one, then if that block has\n * its own `blocks` fields it recurses against the same map.\n */\nexport function buildBlockNestingMap(\n collections: CollectionConfig[],\n blocks: Block[],\n): BlockNestingMap {\n const knownSlugs = new Set(blocks.map((b) => b.slug))\n const edges: BlockNestingMap = []\n\n for (const collection of collections) {\n edges.push(\n ...collectBlocksFieldEdges(collection.fields, {\n owner: collection.slug,\n ownerType: 'collection',\n prefix: '',\n knownSlugs,\n }),\n )\n }\n\n for (const block of blocks) {\n edges.push(\n ...collectBlocksFieldEdges(block.fields, {\n owner: block.slug,\n ownerType: 'block',\n prefix: '',\n knownSlugs,\n }),\n )\n }\n\n return edges\n}\n\n/**\n * Build a relationship graph from introspected collection schemas.\n */\nexport function buildRelationshipGraph(\n schemas: Map<string, CollectionSchema>,\n): RelationshipEdge[] {\n const edges: RelationshipEdge[] = []\n for (const [slug, schema] of schemas) {\n for (const rel of schema.relationships) {\n edges.push({\n fromCollection: slug,\n fieldName: rel.fieldName,\n toCollection: rel.relationTo,\n hasMany: rel.hasMany,\n })\n }\n }\n return edges\n}\n\n// ─── Internal helpers ──────────────────────────────────────────────\n\n/**\n * Recursively extract field metadata from a Payload fields array.\n * Handles tabs, groups, arrays, rows, and collapsible containers.\n */\nfunction extractFields(fields: Field[]): FieldSchema[] {\n const result: FieldSchema[] = []\n\n for (const field of fields) {\n if ('name' in field && field.name) {\n const schema: FieldSchema = {\n name: field.name,\n type: field.type,\n }\n\n if ('required' in field && field.required) schema.required = true\n if ('hasMany' in field && field.hasMany) schema.hasMany = true\n if ('relationTo' in field && field.relationTo) {\n schema.relationTo = field.relationTo as string | string[]\n }\n if ('maxRows' in field && field.maxRows) schema.maxRows = field.maxRows\n\n if (field.type === 'select' && 'options' in field && Array.isArray(field.options)) {\n schema.options = field.options.map((opt) =>\n typeof opt === 'string'\n ? { label: opt, value: opt }\n : { label: String(opt.label), value: String(opt.value) },\n )\n }\n\n if (field.type === 'array' && 'fields' in field) {\n schema.fields = extractFields(field.fields)\n }\n if (field.type === 'group' && 'fields' in field) {\n schema.fields = extractFields(field.fields)\n }\n\n result.push(schema)\n }\n\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if ('fields' in tab) {\n result.push(...extractFields(tab.fields))\n }\n }\n }\n if (field.type === 'row' && 'fields' in field) {\n result.push(...extractFields(field.fields))\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n result.push(...extractFields(field.fields))\n }\n }\n\n return result\n}\n\n/**\n * Extract relationship metadata from fields (for the relationship graph).\n */\nfunction extractRelationships(\n fields: Field[],\n prefix = '',\n): Array<{ fieldName: string; relationTo: string | string[]; hasMany: boolean }> {\n const rels: Array<{ fieldName: string; relationTo: string | string[]; hasMany: boolean }> = []\n\n for (const field of fields) {\n const fieldName = 'name' in field && field.name ? `${prefix}${field.name}` : prefix\n\n if (field.type === 'relationship' && 'relationTo' in field) {\n rels.push({\n fieldName,\n relationTo: field.relationTo as string | string[],\n hasMany: !!('hasMany' in field && field.hasMany),\n })\n }\n\n if (field.type === 'upload' && 'relationTo' in field) {\n rels.push({\n fieldName,\n relationTo: field.relationTo as string,\n hasMany: !!('hasMany' in field && field.hasMany),\n })\n }\n\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if ('fields' in tab) {\n rels.push(...extractRelationships(tab.fields, prefix))\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, `${fieldName}.`))\n }\n if (field.type === 'array' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, `${fieldName}[].`))\n }\n if (field.type === 'row' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, prefix))\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n rels.push(...extractRelationships(field.fields, prefix))\n }\n }\n\n return rels\n}\n\ninterface NestingScanContext {\n owner: string\n ownerType: 'collection' | 'block'\n prefix: string\n knownSlugs: Set<string>\n}\n\n/**\n * Walk fields recording every `blocks`-typed field encountered, including\n * those nested in tabs/rows/groups/arrays/collapsibles. Each entry carries\n * the dotted path from the owner root to the field.\n */\nfunction collectBlocksFieldEdges(fields: Field[], ctx: NestingScanContext): BlockNestingMap {\n const edges: BlockNestingMap = []\n\n for (const field of fields) {\n if (field.type === 'blocks') {\n const fieldName = 'name' in field && field.name ? field.name : ''\n const fullPath = ctx.prefix ? `${ctx.prefix}.${fieldName}` : fieldName\n const allSlugs = readBlockSlugs(field as Field & { type: 'blocks' })\n const acceptedSlugs = allSlugs.filter((s) => ctx.knownSlugs.has(s))\n\n const edge: BlockNestingMap[number] = {\n owner: ctx.owner,\n ownerType: ctx.ownerType,\n fieldPath: fullPath,\n acceptedBlockSlugs: acceptedSlugs,\n }\n const maxRows = (field as Field & { type: 'blocks' }).maxRows\n if (typeof maxRows === 'number') edge.maxRows = maxRows\n edges.push(edge)\n continue\n }\n\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n if (!('fields' in tab)) continue\n const tabName = 'name' in tab && tab.name ? tab.name : ''\n const tabPrefix = tabName\n ? ctx.prefix\n ? `${ctx.prefix}.${tabName}`\n : tabName\n : ctx.prefix\n edges.push(...collectBlocksFieldEdges(tab.fields, { ...ctx, prefix: tabPrefix }))\n }\n continue\n }\n if (field.type === 'row' && 'fields' in field) {\n edges.push(...collectBlocksFieldEdges(field.fields, ctx))\n continue\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n edges.push(...collectBlocksFieldEdges(field.fields, ctx))\n continue\n }\n if (field.type === 'group' && 'fields' in field && 'name' in field && field.name) {\n const newPrefix = ctx.prefix ? `${ctx.prefix}.${field.name}` : field.name\n edges.push(...collectBlocksFieldEdges(field.fields, { ...ctx, prefix: newPrefix }))\n continue\n }\n if (field.type === 'array' && 'fields' in field && 'name' in field && field.name) {\n const newPrefix = ctx.prefix ? `${ctx.prefix}.${field.name}[]` : `${field.name}[]`\n edges.push(...collectBlocksFieldEdges(field.fields, { ...ctx, prefix: newPrefix }))\n continue\n }\n }\n\n return edges\n}\n\n/**\n * Read block slugs from a blocks-typed field, handling both resolved\n * (field.blocks contains objects) and unresolved (field.blockReferences\n * holds slug strings) forms.\n */\nfunction readBlockSlugs(field: Field & { type: 'blocks' }): string[] {\n const f = field as any\n\n if (\n Array.isArray(f.blocks) &&\n f.blocks.length > 0 &&\n typeof f.blocks[0] === 'object' &&\n f.blocks[0]?.slug\n ) {\n return f.blocks.map((b: { slug: string }) => b.slug)\n }\n\n if (Array.isArray(f.blockReferences) && f.blockReferences.length > 0) {\n return f.blockReferences.filter((ref: unknown) => typeof ref === 'string') as string[]\n }\n\n return []\n}\n"],"names":["introspectCollection","collection","fields","extractFields","relationships","extractRelationships","searchableFields","filter","f","includes","type","name","map","hasDrafts","versions","drafts","hasLivePreview","admin","livePreview","slug","introspectCollections","collections","Map","set","introspectBlocks","blocks","catalog","block","buildBlockNestingMap","knownSlugs","Set","b","edges","push","collectBlocksFieldEdges","owner","ownerType","prefix","buildRelationshipGraph","schemas","schema","rel","fromCollection","fieldName","toCollection","relationTo","hasMany","result","field","required","maxRows","Array","isArray","options","opt","label","value","String","tab","tabs","rels","ctx","fullPath","allSlugs","readBlockSlugs","acceptedSlugs","s","has","edge","fieldPath","acceptedBlockSlugs","tabName","tabPrefix","newPrefix","length","blockReferences","ref"],"mappings":"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"}
|
package/dist/prompts.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { BlockCatalog, CollectionSchema, DomainPrompt, RelationshipEdge } from './types';
|
|
1
|
+
import type { BlockCatalog, BlockNestingMap, CollectionSchema, DomainPrompt, RelationshipEdge } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Generate MCP prompts that teach the AI about the content model.
|
|
4
4
|
*
|
|
5
|
-
* Auto-generates
|
|
6
|
-
* draft workflow guide
|
|
5
|
+
* Auto-generates content model overview, block composition guide, and
|
|
6
|
+
* draft workflow guide. User-supplied domain prompts are appended.
|
|
7
7
|
*/
|
|
8
|
-
export declare function generatePrompts(schemas: Map<string, CollectionSchema>, catalog: BlockCatalog, relationships: RelationshipEdge[], domainPrompts?: DomainPrompt[]): {
|
|
8
|
+
export declare function generatePrompts(schemas: Map<string, CollectionSchema>, catalog: BlockCatalog, nesting: BlockNestingMap, relationships: RelationshipEdge[], domainPrompts?: DomainPrompt[]): {
|
|
9
9
|
name: string;
|
|
10
10
|
title: string;
|
|
11
11
|
description: string;
|
package/dist/prompts.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generate MCP prompts that teach the AI about the content model.
|
|
3
3
|
*
|
|
4
|
-
* Auto-generates
|
|
5
|
-
* draft workflow guide
|
|
6
|
-
*/ export function generatePrompts(schemas, catalog, relationships, domainPrompts) {
|
|
4
|
+
* Auto-generates content model overview, block composition guide, and
|
|
5
|
+
* draft workflow guide. User-supplied domain prompts are appended.
|
|
6
|
+
*/ export function generatePrompts(schemas, catalog, nesting, relationships, domainPrompts) {
|
|
7
7
|
const prompts = [
|
|
8
8
|
buildContentModelOverview(schemas, relationships),
|
|
9
|
-
buildBlockCompositionGuide(catalog),
|
|
9
|
+
buildBlockCompositionGuide(catalog, nesting),
|
|
10
10
|
buildDraftWorkflowGuide(schemas)
|
|
11
11
|
];
|
|
12
12
|
if (domainPrompts?.length) {
|
|
@@ -49,7 +49,6 @@ function buildContentModelOverview(schemas, relationships) {
|
|
|
49
49
|
lines.push(`Draft support: ${schema.hasDrafts ? 'yes' : 'no'}`);
|
|
50
50
|
lines.push(`Live preview: ${schema.hasLivePreview ? 'yes' : 'no'}`);
|
|
51
51
|
lines.push('');
|
|
52
|
-
// Fields summary
|
|
53
52
|
lines.push('### Fields');
|
|
54
53
|
for (const field of schema.fields){
|
|
55
54
|
const parts = [
|
|
@@ -69,7 +68,6 @@ function buildContentModelOverview(schemas, relationships) {
|
|
|
69
68
|
lines.push(parts.join(''));
|
|
70
69
|
}
|
|
71
70
|
lines.push('');
|
|
72
|
-
// Relationships
|
|
73
71
|
const collRels = relationships.filter((r)=>r.fromCollection === slug);
|
|
74
72
|
if (collRels.length > 0) {
|
|
75
73
|
lines.push('### Relationships');
|
|
@@ -94,47 +92,58 @@ function buildContentModelOverview(schemas, relationships) {
|
|
|
94
92
|
}
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
|
-
function buildBlockCompositionGuide(catalog) {
|
|
95
|
+
function buildBlockCompositionGuide(catalog, nesting) {
|
|
98
96
|
return {
|
|
99
97
|
name: 'blockCompositionGuide',
|
|
100
98
|
title: 'Block Composition Guide',
|
|
101
|
-
description: '
|
|
99
|
+
description: 'Lists every block type, its fields, and which slugs each blocks-typed field accepts. Use this with the relationshipGraph and collectionSchema resources to compose layouts at any depth.',
|
|
102
100
|
handler () {
|
|
103
101
|
const lines = [
|
|
104
102
|
'# Block Composition Guide',
|
|
105
103
|
'',
|
|
106
|
-
'
|
|
104
|
+
'Every block has a `blockType` discriminator plus its own fields. A block may include one or more `blocks`-typed fields that nest other blocks. The accepted slugs per field are listed below — recurse into the same map for deeper nesting.',
|
|
107
105
|
''
|
|
108
106
|
];
|
|
109
|
-
|
|
110
|
-
lines.push('
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
lines.push(`Maximum ${section.maxRows} leaf block(s).`);
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
lines.push(`Accepts all leaf blocks: ${section.acceptedLeafSlugs.join(', ')}`);
|
|
107
|
+
lines.push('## Where blocks can nest');
|
|
108
|
+
lines.push('');
|
|
109
|
+
const collectionEdges = nesting.filter((e)=>e.ownerType === 'collection');
|
|
110
|
+
const blockEdges = nesting.filter((e)=>e.ownerType === 'block');
|
|
111
|
+
if (collectionEdges.length > 0) {
|
|
112
|
+
lines.push('### In collections');
|
|
113
|
+
for (const edge of collectionEdges){
|
|
114
|
+
const cap = edge.maxRows ? ` (max ${edge.maxRows})` : '';
|
|
115
|
+
lines.push(`- \`${edge.owner}.${edge.fieldPath}\`${cap} accepts: ${edge.acceptedBlockSlugs.join(', ') || '(none)'}`);
|
|
122
116
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
117
|
+
lines.push('');
|
|
118
|
+
}
|
|
119
|
+
if (blockEdges.length > 0) {
|
|
120
|
+
lines.push('### In blocks (nested composition)');
|
|
121
|
+
for (const edge of blockEdges){
|
|
122
|
+
const cap = edge.maxRows ? ` (max ${edge.maxRows})` : '';
|
|
123
|
+
lines.push(`- block \`${edge.owner}\` field \`${edge.fieldPath}\`${cap} accepts: ${edge.acceptedBlockSlugs.join(', ') || '(none)'}`);
|
|
128
124
|
}
|
|
129
125
|
lines.push('');
|
|
130
126
|
}
|
|
131
|
-
|
|
132
|
-
lines.push('
|
|
133
|
-
for (const
|
|
134
|
-
lines.push(`### ${
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
lines.push('## Block fields');
|
|
128
|
+
lines.push('');
|
|
129
|
+
for (const block of catalog.blocks){
|
|
130
|
+
lines.push(`### ${block.slug}`);
|
|
131
|
+
if (block.fields.length === 0) {
|
|
132
|
+
lines.push('(no fields)');
|
|
133
|
+
} else {
|
|
134
|
+
for (const f of block.fields){
|
|
135
|
+
const parts = [
|
|
136
|
+
`- ${f.name} (${f.type})`
|
|
137
|
+
];
|
|
138
|
+
if (f.required) parts.push(' *required*');
|
|
139
|
+
if (f.options?.length) {
|
|
140
|
+
parts.push(` [${f.options.map((o)=>o.value).join(', ')}]`);
|
|
141
|
+
}
|
|
142
|
+
if (f.relationTo) {
|
|
143
|
+
const targets = Array.isArray(f.relationTo) ? f.relationTo.join(', ') : f.relationTo;
|
|
144
|
+
parts.push(` → ${targets}`);
|
|
145
|
+
}
|
|
146
|
+
lines.push(parts.join(''));
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
lines.push('');
|
|
@@ -184,7 +193,7 @@ function buildDraftWorkflowGuide(schemas) {
|
|
|
184
193
|
lines.push('### How drafts work');
|
|
185
194
|
lines.push('1. When you create or update a document in a draft-enabled collection, set `_status: "draft"` to keep it unpublished.');
|
|
186
195
|
lines.push('2. Draft documents are only visible via preview URLs or the admin panel — they are not public.');
|
|
187
|
-
lines.push('3. To publish a draft,
|
|
196
|
+
lines.push('3. To publish a draft, use the `publishDraft` tool (raw `update` is locked on always-draft collections).');
|
|
188
197
|
lines.push('4. You can review a draft via its preview URL before publishing.');
|
|
189
198
|
}
|
|
190
199
|
lines.push('');
|
package/dist/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/prompts.ts"],"sourcesContent":["import type {\n BlockCatalog,\n CollectionSchema,\n DomainPrompt,\n RelationshipEdge,\n} from './types'\n\n/**\n * Generate MCP prompts that teach the AI about the content model.\n *\n * Auto-generates three prompts (content model overview, block composition guide,\n * draft workflow guide) and merges with any user-provided domain prompts.\n */\nexport function generatePrompts(\n schemas: Map<string, CollectionSchema>,\n catalog: BlockCatalog,\n relationships: RelationshipEdge[],\n domainPrompts?: DomainPrompt[],\n) {\n const prompts = [\n buildContentModelOverview(schemas, relationships),\n buildBlockCompositionGuide(catalog),\n buildDraftWorkflowGuide(schemas),\n ]\n\n if (domainPrompts?.length) {\n for (const dp of domainPrompts) {\n prompts.push({\n name: dp.name,\n title: dp.title,\n description: dp.description,\n handler() {\n return {\n messages: [\n {\n content: { type: 'text' as const, text: dp.content },\n role: 'user' as const,\n },\n ],\n }\n },\n })\n }\n }\n\n return prompts\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────\n\nfunction buildContentModelOverview(\n schemas: Map<string, CollectionSchema>,\n relationships: RelationshipEdge[],\n) {\n return {\n name: 'contentModelOverview',\n title: 'Content Model Overview',\n description:\n 'Describes every collection in the CMS — its purpose, fields, and relationships to other collections.',\n handler() {\n const lines: string[] = ['# Content Model Overview', '']\n\n for (const [slug, schema] of schemas) {\n lines.push(`## Collection: ${slug}`)\n lines.push(`Draft support: ${schema.hasDrafts ? 'yes' : 'no'}`)\n lines.push(`Live preview: ${schema.hasLivePreview ? 'yes' : 'no'}`)\n lines.push('')\n\n // Fields summary\n lines.push('### Fields')\n for (const field of schema.fields) {\n const parts = [`- **${field.name}** (${field.type})`]\n if (field.required) parts.push(' *required*')\n if (field.hasMany) parts.push(' hasMany')\n if (field.relationTo) {\n const targets = Array.isArray(field.relationTo)\n ? field.relationTo.join(', ')\n : field.relationTo\n parts.push(` → ${targets}`)\n }\n if (field.options?.length) {\n const vals = field.options.map((o) => o.value).join(', ')\n parts.push(` [${vals}]`)\n }\n if (field.maxRows) parts.push(` maxRows: ${field.maxRows}`)\n lines.push(parts.join(''))\n }\n lines.push('')\n\n // Relationships\n const collRels = relationships.filter((r) => r.fromCollection === slug)\n if (collRels.length > 0) {\n lines.push('### Relationships')\n for (const rel of collRels) {\n const targets = Array.isArray(rel.toCollection)\n ? rel.toCollection.join(', ')\n : rel.toCollection\n lines.push(\n `- ${rel.fieldName} → ${targets}${rel.hasMany ? ' (hasMany)' : ''}`,\n )\n }\n lines.push('')\n }\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n\nfunction buildBlockCompositionGuide(catalog: BlockCatalog) {\n return {\n name: 'blockCompositionGuide',\n title: 'Block Composition Guide',\n description:\n 'Explains the section/leaf block hierarchy, valid nesting rules, and how to compose page layouts.',\n handler() {\n const lines: string[] = [\n '# Block Composition Guide',\n '',\n 'Pages are built from **section** blocks. Each section can contain **leaf** blocks according to its nesting rules.',\n '',\n ]\n\n // Section blocks\n lines.push('## Section Blocks')\n for (const section of catalog.sections) {\n lines.push(`### ${section.slug} (${section.nestingType})`)\n\n if (section.nestingType === 'fixed') {\n lines.push('This section has no nested blocks — configure it with its own fields only.')\n } else if (section.nestingType === 'constrained') {\n lines.push(\n `Accepts only: ${section.acceptedLeafSlugs.join(', ')}`,\n )\n if (section.maxRows) {\n lines.push(`Maximum ${section.maxRows} leaf block(s).`)\n }\n } else {\n lines.push(\n `Accepts all leaf blocks: ${section.acceptedLeafSlugs.join(', ')}`,\n )\n }\n\n if (section.fields.length > 0) {\n lines.push('Section-level fields:')\n for (const f of section.fields) {\n lines.push(` - ${f.name} (${f.type})${f.required ? ' *required*' : ''}`)\n }\n }\n lines.push('')\n }\n\n // Leaf blocks\n lines.push('## Leaf Blocks')\n for (const leaf of catalog.leaves) {\n lines.push(`### ${leaf.slug}`)\n if (leaf.fields.length > 0) {\n for (const f of leaf.fields) {\n lines.push(` - ${f.name} (${f.type})${f.required ? ' *required*' : ''}`)\n }\n }\n lines.push('')\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n\nfunction buildDraftWorkflowGuide(schemas: Map<string, CollectionSchema>) {\n return {\n name: 'draftWorkflowGuide',\n title: 'Draft Workflow Guide',\n description:\n 'Explains which collections support drafts, how to create drafts, review them, and publish.',\n handler() {\n const draftCollections: string[] = []\n const publishCollections: string[] = []\n\n for (const [slug, schema] of schemas) {\n if (schema.hasDrafts) {\n draftCollections.push(slug)\n } else {\n publishCollections.push(slug)\n }\n }\n\n const lines: string[] = [\n '# Draft Workflow Guide',\n '',\n '## Collections with draft support',\n '',\n ]\n\n if (draftCollections.length === 0) {\n lines.push('No collections have draft support enabled.')\n } else {\n for (const slug of draftCollections) {\n lines.push(`- **${slug}**`)\n }\n lines.push('')\n lines.push('### How drafts work')\n lines.push(\n '1. When you create or update a document in a draft-enabled collection, set `_status: \"draft\"` to keep it unpublished.',\n )\n lines.push(\n '2. Draft documents are only visible via preview URLs or the admin panel — they are not public.',\n )\n lines.push(\n '3. To publish a draft, update the document with `_status: \"published\"` or use the `publishDraft` tool.',\n )\n lines.push(\n '4. You can review a draft via its preview URL before publishing.',\n )\n }\n\n lines.push('')\n lines.push('## Collections without draft support')\n lines.push('')\n\n if (publishCollections.length === 0) {\n lines.push('All collections support drafts.')\n } else {\n for (const slug of publishCollections) {\n lines.push(`- **${slug}** — changes are published immediately`)\n }\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n"],"names":["generatePrompts","schemas","catalog","relationships","domainPrompts","prompts","buildContentModelOverview","buildBlockCompositionGuide","buildDraftWorkflowGuide","length","dp","push","name","title","description","handler","messages","content","type","text","role","lines","slug","schema","hasDrafts","hasLivePreview","field","fields","parts","required","hasMany","relationTo","targets","Array","isArray","join","options","vals","map","o","value","maxRows","collRels","filter","r","fromCollection","rel","toCollection","fieldName","section","sections","nestingType","acceptedLeafSlugs","f","leaf","leaves","draftCollections","publishCollections"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/prompts.ts"],"sourcesContent":["import type {\n BlockCatalog,\n BlockNestingMap,\n CollectionSchema,\n DomainPrompt,\n RelationshipEdge,\n} from './types'\n\n/**\n * Generate MCP prompts that teach the AI about the content model.\n *\n * Auto-generates content model overview, block composition guide, and\n * draft workflow guide. User-supplied domain prompts are appended.\n */\nexport function generatePrompts(\n schemas: Map<string, CollectionSchema>,\n catalog: BlockCatalog,\n nesting: BlockNestingMap,\n relationships: RelationshipEdge[],\n domainPrompts?: DomainPrompt[],\n) {\n const prompts = [\n buildContentModelOverview(schemas, relationships),\n buildBlockCompositionGuide(catalog, nesting),\n buildDraftWorkflowGuide(schemas),\n ]\n\n if (domainPrompts?.length) {\n for (const dp of domainPrompts) {\n prompts.push({\n name: dp.name,\n title: dp.title,\n description: dp.description,\n handler() {\n return {\n messages: [\n {\n content: { type: 'text' as const, text: dp.content },\n role: 'user' as const,\n },\n ],\n }\n },\n })\n }\n }\n\n return prompts\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────\n\nfunction buildContentModelOverview(\n schemas: Map<string, CollectionSchema>,\n relationships: RelationshipEdge[],\n) {\n return {\n name: 'contentModelOverview',\n title: 'Content Model Overview',\n description:\n 'Describes every collection in the CMS — its purpose, fields, and relationships to other collections.',\n handler() {\n const lines: string[] = ['# Content Model Overview', '']\n\n for (const [slug, schema] of schemas) {\n lines.push(`## Collection: ${slug}`)\n lines.push(`Draft support: ${schema.hasDrafts ? 'yes' : 'no'}`)\n lines.push(`Live preview: ${schema.hasLivePreview ? 'yes' : 'no'}`)\n lines.push('')\n\n lines.push('### Fields')\n for (const field of schema.fields) {\n const parts = [`- **${field.name}** (${field.type})`]\n if (field.required) parts.push(' *required*')\n if (field.hasMany) parts.push(' hasMany')\n if (field.relationTo) {\n const targets = Array.isArray(field.relationTo)\n ? field.relationTo.join(', ')\n : field.relationTo\n parts.push(` → ${targets}`)\n }\n if (field.options?.length) {\n const vals = field.options.map((o) => o.value).join(', ')\n parts.push(` [${vals}]`)\n }\n if (field.maxRows) parts.push(` maxRows: ${field.maxRows}`)\n lines.push(parts.join(''))\n }\n lines.push('')\n\n const collRels = relationships.filter((r) => r.fromCollection === slug)\n if (collRels.length > 0) {\n lines.push('### Relationships')\n for (const rel of collRels) {\n const targets = Array.isArray(rel.toCollection)\n ? rel.toCollection.join(', ')\n : rel.toCollection\n lines.push(`- ${rel.fieldName} → ${targets}${rel.hasMany ? ' (hasMany)' : ''}`)\n }\n lines.push('')\n }\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n\nfunction buildBlockCompositionGuide(catalog: BlockCatalog, nesting: BlockNestingMap) {\n return {\n name: 'blockCompositionGuide',\n title: 'Block Composition Guide',\n description:\n 'Lists every block type, its fields, and which slugs each blocks-typed field accepts. Use this with the relationshipGraph and collectionSchema resources to compose layouts at any depth.',\n handler() {\n const lines: string[] = [\n '# Block Composition Guide',\n '',\n 'Every block has a `blockType` discriminator plus its own fields. A block may include one or more `blocks`-typed fields that nest other blocks. The accepted slugs per field are listed below — recurse into the same map for deeper nesting.',\n '',\n ]\n\n lines.push('## Where blocks can nest')\n lines.push('')\n const collectionEdges = nesting.filter((e) => e.ownerType === 'collection')\n const blockEdges = nesting.filter((e) => e.ownerType === 'block')\n\n if (collectionEdges.length > 0) {\n lines.push('### In collections')\n for (const edge of collectionEdges) {\n const cap = edge.maxRows ? ` (max ${edge.maxRows})` : ''\n lines.push(\n `- \\`${edge.owner}.${edge.fieldPath}\\`${cap} accepts: ${edge.acceptedBlockSlugs.join(', ') || '(none)'}`,\n )\n }\n lines.push('')\n }\n\n if (blockEdges.length > 0) {\n lines.push('### In blocks (nested composition)')\n for (const edge of blockEdges) {\n const cap = edge.maxRows ? ` (max ${edge.maxRows})` : ''\n lines.push(\n `- block \\`${edge.owner}\\` field \\`${edge.fieldPath}\\`${cap} accepts: ${edge.acceptedBlockSlugs.join(', ') || '(none)'}`,\n )\n }\n lines.push('')\n }\n\n lines.push('## Block fields')\n lines.push('')\n for (const block of catalog.blocks) {\n lines.push(`### ${block.slug}`)\n if (block.fields.length === 0) {\n lines.push('(no fields)')\n } else {\n for (const f of block.fields) {\n const parts = [`- ${f.name} (${f.type})`]\n if (f.required) parts.push(' *required*')\n if (f.options?.length) {\n parts.push(` [${f.options.map((o) => o.value).join(', ')}]`)\n }\n if (f.relationTo) {\n const targets = Array.isArray(f.relationTo)\n ? f.relationTo.join(', ')\n : f.relationTo\n parts.push(` → ${targets}`)\n }\n lines.push(parts.join(''))\n }\n }\n lines.push('')\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n\nfunction buildDraftWorkflowGuide(schemas: Map<string, CollectionSchema>) {\n return {\n name: 'draftWorkflowGuide',\n title: 'Draft Workflow Guide',\n description:\n 'Explains which collections support drafts, how to create drafts, review them, and publish.',\n handler() {\n const draftCollections: string[] = []\n const publishCollections: string[] = []\n\n for (const [slug, schema] of schemas) {\n if (schema.hasDrafts) {\n draftCollections.push(slug)\n } else {\n publishCollections.push(slug)\n }\n }\n\n const lines: string[] = ['# Draft Workflow Guide', '', '## Collections with draft support', '']\n\n if (draftCollections.length === 0) {\n lines.push('No collections have draft support enabled.')\n } else {\n for (const slug of draftCollections) {\n lines.push(`- **${slug}**`)\n }\n lines.push('')\n lines.push('### How drafts work')\n lines.push(\n '1. When you create or update a document in a draft-enabled collection, set `_status: \"draft\"` to keep it unpublished.',\n )\n lines.push(\n '2. Draft documents are only visible via preview URLs or the admin panel — they are not public.',\n )\n lines.push(\n '3. To publish a draft, use the `publishDraft` tool (raw `update` is locked on always-draft collections).',\n )\n lines.push('4. You can review a draft via its preview URL before publishing.')\n }\n\n lines.push('')\n lines.push('## Collections without draft support')\n lines.push('')\n\n if (publishCollections.length === 0) {\n lines.push('All collections support drafts.')\n } else {\n for (const slug of publishCollections) {\n lines.push(`- **${slug}** — changes are published immediately`)\n }\n }\n\n return {\n messages: [\n {\n content: { type: 'text' as const, text: lines.join('\\n') },\n role: 'user' as const,\n },\n ],\n }\n },\n }\n}\n"],"names":["generatePrompts","schemas","catalog","nesting","relationships","domainPrompts","prompts","buildContentModelOverview","buildBlockCompositionGuide","buildDraftWorkflowGuide","length","dp","push","name","title","description","handler","messages","content","type","text","role","lines","slug","schema","hasDrafts","hasLivePreview","field","fields","parts","required","hasMany","relationTo","targets","Array","isArray","join","options","vals","map","o","value","maxRows","collRels","filter","r","fromCollection","rel","toCollection","fieldName","collectionEdges","e","ownerType","blockEdges","edge","cap","owner","fieldPath","acceptedBlockSlugs","block","blocks","f","draftCollections","publishCollections"],"mappings":"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"}
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import type { BlockCatalog, CollectionSchema, RelationshipEdge } from './types';
|
|
1
|
+
import type { BlockCatalog, BlockNestingMap, CollectionSchema, RelationshipEdge } from './types';
|
|
2
2
|
/**
|
|
3
|
-
* Generate MCP resources that expose the
|
|
4
|
-
*
|
|
3
|
+
* Generate MCP resources that expose the introspected schema as static JSON.
|
|
4
|
+
*
|
|
5
|
+
* Four resources:
|
|
6
|
+
* - blocks://catalog — flat list of every block and its fields
|
|
7
|
+
* - blocks://nesting — per-blocks-field map of which slugs each field accepts
|
|
8
|
+
* - collections://schema — collection field metadata
|
|
9
|
+
* - collections://relationships — collection relationship graph
|
|
5
10
|
*/
|
|
6
|
-
export declare function generateResources(schemas: Map<string, CollectionSchema>, catalog: BlockCatalog, relationships: RelationshipEdge[]): {
|
|
11
|
+
export declare function generateResources(schemas: Map<string, CollectionSchema>, catalog: BlockCatalog, nesting: BlockNestingMap, relationships: RelationshipEdge[]): {
|
|
7
12
|
name: string;
|
|
8
13
|
title: string;
|
|
9
14
|
description: string;
|