@axinom/mosaic-agent-skills 0.0.1
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 +121 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/tools/graphql/index.d.ts +3 -0
- package/dist/tools/graphql/index.d.ts.map +1 -0
- package/dist/tools/graphql/index.js +84 -0
- package/dist/tools/graphql/index.js.map +1 -0
- package/dist/tools/graphql/tools.d.ts +71 -0
- package/dist/tools/graphql/tools.d.ts.map +1 -0
- package/dist/tools/graphql/tools.js +187 -0
- package/dist/tools/graphql/tools.js.map +1 -0
- package/dist/tools/graphql/utils.d.ts +20 -0
- package/dist/tools/graphql/utils.d.ts.map +1 -0
- package/dist/tools/graphql/utils.js +140 -0
- package/dist/tools/graphql/utils.js.map +1 -0
- package/dist/tools/skills/index.d.ts +3 -0
- package/dist/tools/skills/index.d.ts.map +1 -0
- package/dist/tools/skills/index.js +62 -0
- package/dist/tools/skills/index.js.map +1 -0
- package/dist/tools/skills/tools.d.ts +5 -0
- package/dist/tools/skills/tools.d.ts.map +1 -0
- package/dist/tools/skills/tools.js +67 -0
- package/dist/tools/skills/tools.js.map +1 -0
- package/dist/tools/skills/types.d.ts +12 -0
- package/dist/tools/skills/types.d.ts.map +1 -0
- package/dist/tools/skills/types.js +3 -0
- package/dist/tools/skills/types.js.map +1 -0
- package/dist/tools/skills/utils.d.ts +11 -0
- package/dist/tools/skills/utils.d.ts.map +1 -0
- package/dist/tools/skills/utils.js +127 -0
- package/dist/tools/skills/utils.js.map +1 -0
- package/package.json +40 -0
- package/skills/_shared/actions/execution-summary.md +53 -0
- package/skills/_shared/actions/typescript-codegen.md +32 -0
- package/skills/_shared/actions/typescript-validation.md +32 -0
- package/skills/_shared/conventions/field-component-mapping.md +155 -0
- package/skills/_shared/conventions/field-validation-schema.md +77 -0
- package/skills/_shared/discovery/discover-paths.md +52 -0
- package/skills/_shared/discovery/extract-entity-features.md +565 -0
- package/skills/generate-create-station/SKILL.md +93 -0
- package/skills/generate-create-station/refs/finalization/station-registration.md +163 -0
- package/skills/generate-create-station/refs/templates/create-form-station.md +206 -0
- package/skills/generate-create-station/refs/templates/graphql-operations.md +56 -0
- package/skills/generate-details-station/SKILL.md +125 -0
- package/skills/generate-details-station/refs/finalization/explorer-integration.md +242 -0
- package/skills/generate-details-station/refs/finalization/station-registration.md +139 -0
- package/skills/generate-details-station/refs/templates/actions.md +127 -0
- package/skills/generate-details-station/refs/templates/breadcrumb.md +67 -0
- package/skills/generate-details-station/refs/templates/details-form-station.md +589 -0
- package/skills/generate-details-station/refs/templates/details-wrapper.md +54 -0
- package/skills/generate-details-station/refs/templates/form-data-types.md +62 -0
- package/skills/generate-details-station/refs/templates/graphql-operations.md +256 -0
- package/skills/generate-details-station/refs/templates/managed-integrations/image-management-station.md +322 -0
- package/skills/generate-details-station/refs/templates/managed-integrations/video-management-station.md +283 -0
- package/skills/generate-explorer-station/SKILL.md +121 -0
- package/skills/generate-explorer-station/refs/finalization/station-registration.md +145 -0
- package/skills/generate-explorer-station/refs/select-columns-filters.md +63 -0
- package/skills/generate-explorer-station/refs/templates/bulk-edit.md +369 -0
- package/skills/generate-explorer-station/refs/templates/common/bulk-actions.md +64 -0
- package/skills/generate-explorer-station/refs/templates/common/columns.md +131 -0
- package/skills/generate-explorer-station/refs/templates/common/data-provider.md +83 -0
- package/skills/generate-explorer-station/refs/templates/common/filters.md +220 -0
- package/skills/generate-explorer-station/refs/templates/common/inline-actions.md +45 -0
- package/skills/generate-explorer-station/refs/templates/common/types.md +28 -0
- package/skills/generate-explorer-station/refs/templates/graphql-operations.md +235 -0
- package/skills/generate-explorer-station/refs/templates/navigation-explorer-station.md +144 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: extract-entity-features
|
|
3
|
+
input:
|
|
4
|
+
- Entity name (PascalCase)
|
|
5
|
+
- schemaPath
|
|
6
|
+
- serviceName
|
|
7
|
+
output:
|
|
8
|
+
- EntityFeatures object
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Extract Entity Features
|
|
12
|
+
|
|
13
|
+
## EntityFeatures Structure
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
/**
|
|
17
|
+
* Identity used for file/folder names, routes, registration labels, URLs
|
|
18
|
+
*/
|
|
19
|
+
interface IdentityFeatures {
|
|
20
|
+
/**
|
|
21
|
+
* PascalCase singular - entity name as-is
|
|
22
|
+
* @example "Movie", "TvShow"
|
|
23
|
+
*/
|
|
24
|
+
name: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* PascalCase plural - pluralize entity name
|
|
28
|
+
* @example "Movies", "TvShows"
|
|
29
|
+
*/
|
|
30
|
+
namePlural: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* camelCase singular - lowercase first character
|
|
34
|
+
* @example "movie", "tvShow"
|
|
35
|
+
*/
|
|
36
|
+
camelCase: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* camelCase plural - pluralize camelCase form
|
|
40
|
+
* @example "movies", "tvShows"
|
|
41
|
+
*/
|
|
42
|
+
camelCasePlural: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* kebab-case plural for routes - lowercase with hyphens
|
|
46
|
+
* @example "movies", "tv-shows"
|
|
47
|
+
*/
|
|
48
|
+
kebabCasePlural: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Main display field - look for field named `title` or `name` in entity type
|
|
52
|
+
* @example "title" (Movie), "name" (Account), "label" (Tag)
|
|
53
|
+
*/
|
|
54
|
+
titleField: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* User-facing display text for the entity name
|
|
58
|
+
* @example "Movie" (Movie), "Tv Show" (TvShow), "Service Account" (ServiceAccount)
|
|
59
|
+
*/
|
|
60
|
+
displayText: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* ID field type - check `id` field type in entity type definition
|
|
64
|
+
* @example "Int" (most entities), "UUID" (some entities)
|
|
65
|
+
*/
|
|
66
|
+
idType: 'Int' | 'UUID';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* GraphQL type names extracted from the GQL Schema for the Entity
|
|
71
|
+
*/
|
|
72
|
+
interface SchemaNames {
|
|
73
|
+
/**
|
|
74
|
+
* Entity `type` name
|
|
75
|
+
* @example "Movie", "Episode", "Genre"
|
|
76
|
+
*/
|
|
77
|
+
entity: string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Filter `input` type - pattern: `{Entity}Filter`
|
|
81
|
+
* @example "MovieFilter", "EpisodeFilter"
|
|
82
|
+
*/
|
|
83
|
+
filter: string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* OrderBy `enum` - pattern: `{Plural}OrderBy`
|
|
87
|
+
* @example "MoviesOrderBy", "EpisodesOrderBy"
|
|
88
|
+
*/
|
|
89
|
+
orderBy: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Condition `input` type - pattern: `{Entity}Condition`
|
|
93
|
+
* @example "MovieCondition", "EpisodeCondition"
|
|
94
|
+
*/
|
|
95
|
+
condition: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Connection `type` - pattern: `{Plural}Connection`
|
|
99
|
+
* @example "MoviesConnection", "EpisodesConnection"
|
|
100
|
+
*/
|
|
101
|
+
connection: string;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Input type - pattern: `{Entity}Input` (if exists in schema)
|
|
105
|
+
* @example "MovieInput", "EpisodeInput"
|
|
106
|
+
*/
|
|
107
|
+
input?: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Patch type - pattern: `{Entity}Patch` (if exists in schema)
|
|
111
|
+
* @example "MoviePatch", "EpisodePatch"
|
|
112
|
+
*/
|
|
113
|
+
patch?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* GraphQL Query field names for the entity - check queries: `{camelPlural}` and `{camel}`
|
|
118
|
+
*/
|
|
119
|
+
interface QueryNames {
|
|
120
|
+
list?: {
|
|
121
|
+
/**
|
|
122
|
+
* Query field name - pattern: `{camelPlural}`
|
|
123
|
+
* @example "movies", "episodes", "collections"
|
|
124
|
+
*/
|
|
125
|
+
field: string;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Return type extracted from query definition
|
|
129
|
+
* @example "MoviesConnection", "EpisodesConnection"
|
|
130
|
+
*/
|
|
131
|
+
returnType: string;
|
|
132
|
+
};
|
|
133
|
+
single?: {
|
|
134
|
+
/**
|
|
135
|
+
* Query field name - pattern: `{camel}`
|
|
136
|
+
* @example "movie", "episode", "collection"
|
|
137
|
+
*/
|
|
138
|
+
field: string;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return type extracted from query definition
|
|
142
|
+
* @example "Movie", "Episode", "Collection"
|
|
143
|
+
*/
|
|
144
|
+
returnType: string;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* GraphQL Mutation field names for the entity
|
|
150
|
+
*/
|
|
151
|
+
interface MutationNames {
|
|
152
|
+
/**
|
|
153
|
+
* Single entity create mutation - pattern: `create{Entity}`
|
|
154
|
+
* @example "createMovie", "createEpisode"
|
|
155
|
+
*/
|
|
156
|
+
create?: string;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Single entity update mutation - pattern: `update{Entity}`
|
|
160
|
+
* @example "updateMovie", "updateEpisode"
|
|
161
|
+
*/
|
|
162
|
+
update?: string;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Single entity delete mutation - pattern: `delete{Entity}`
|
|
166
|
+
* @example "deleteMovie", "deleteEpisode"
|
|
167
|
+
*/
|
|
168
|
+
delete?: string;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Bulk edit mutation - pattern: `bulkEdit{Plural}Async`
|
|
172
|
+
* @example "bulkEditMoviesAsync", "bulkEditEpisodesAsync"
|
|
173
|
+
*/
|
|
174
|
+
bulkEdit?: string;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Bulk action mutations - search for `Mutation.{verb}{Plural}` pattern
|
|
178
|
+
* @example ["deleteMovies", "publishMovies", "unpublishMovies", "archiveMovies"]
|
|
179
|
+
*/
|
|
180
|
+
bulkActions?: string[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* GraphQL Subscription for the entity - check subscription: `{camel}Mutated`
|
|
185
|
+
*/
|
|
186
|
+
interface SubscriptionNames {
|
|
187
|
+
mutated?: {
|
|
188
|
+
/**
|
|
189
|
+
* Subscription field name - pattern: `{camel}Mutated`
|
|
190
|
+
* @example "movieMutated", "episodeMutated"
|
|
191
|
+
*/
|
|
192
|
+
field: string;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Payload type extracted from subscription definition
|
|
196
|
+
* @example "MovieSubscriptionPayload", "EpisodeSubscriptionPayload"
|
|
197
|
+
*/
|
|
198
|
+
payloadType: string;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Event key enum - pattern: `{Entity}SubscriptionEventKey`
|
|
202
|
+
* @example "MovieSubscriptionEventKey", "EpisodeSubscriptionEventKey"
|
|
203
|
+
*/
|
|
204
|
+
eventKeyEnum: string;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
interface MutationFeatures {
|
|
209
|
+
/**
|
|
210
|
+
* True if `create{Entity}` mutation exists
|
|
211
|
+
*/
|
|
212
|
+
create: boolean;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* True if `update{Entity}` mutation exists
|
|
216
|
+
*/
|
|
217
|
+
update: boolean;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* True if `delete{Entity}` mutation exists
|
|
221
|
+
*/
|
|
222
|
+
delete: boolean;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* True if `bulkEdit{Plural}Async` mutation exists
|
|
226
|
+
*/
|
|
227
|
+
bulkEdit: boolean;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* True if any bulk action mutations found (pattern: `{verb}{Plural}`)
|
|
231
|
+
*/
|
|
232
|
+
bulkActions: boolean;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface QueryFeatures {
|
|
236
|
+
/**
|
|
237
|
+
* True if list query (`{camelPlural}`) exists
|
|
238
|
+
*/
|
|
239
|
+
list: boolean;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* True if single query (`{camel}`) exists
|
|
243
|
+
*/
|
|
244
|
+
single: boolean;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* True if subscription (`{camel}Mutated`) exists
|
|
248
|
+
*/
|
|
249
|
+
subscription: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Image management capability for the entity - look for `{camel}Images` connection and `{Entity}ImageType` enum
|
|
254
|
+
*/
|
|
255
|
+
interface ImageFeatures {
|
|
256
|
+
/**
|
|
257
|
+
* Connection field name - pattern: `{camel}Images`
|
|
258
|
+
* @example "moviesImages", "episodesImages"
|
|
259
|
+
*/
|
|
260
|
+
connectionField: string;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Node type - pattern: `{Plural}Image`
|
|
264
|
+
* @example "MoviesImage", "EpisodesImage"
|
|
265
|
+
*/
|
|
266
|
+
nodeType: string;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Image type enum - pattern: `{Entity}ImageType`
|
|
270
|
+
* @example "MovieImageType", "EpisodeImageType"
|
|
271
|
+
*/
|
|
272
|
+
imageTypeEnum: string;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Enum values extracted from type definition
|
|
276
|
+
* @example ["COVER", "TEASER"]
|
|
277
|
+
*/
|
|
278
|
+
imageTypeValues: string[];
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Entity scope for image management (camelCase)
|
|
282
|
+
* @example "movie", "episode"
|
|
283
|
+
*/
|
|
284
|
+
scope: string;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Video management capability for the entity - look for `mainVideoId` field and `{camel}Trailers` connection
|
|
289
|
+
*/
|
|
290
|
+
interface VideoFeatures {
|
|
291
|
+
/**
|
|
292
|
+
* Main video field (check entity type for this field)
|
|
293
|
+
* @example "mainVideoId"
|
|
294
|
+
*/
|
|
295
|
+
mainVideoField?: string;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Trailers connection field - pattern: `{camel}Trailers`
|
|
299
|
+
* @example "moviesTrailers", "episodesTrailers"
|
|
300
|
+
*/
|
|
301
|
+
trailersConnection?: string;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Trailers node type - pattern: `{Plural}Trailer`
|
|
305
|
+
* @example "MoviesTrailer", "EpisodesTrailer"
|
|
306
|
+
*/
|
|
307
|
+
trailersNodeType?: string;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface CapabilityFeatures {
|
|
311
|
+
images?: ImageFeatures;
|
|
312
|
+
videos?: VideoFeatures;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
interface ScalarFieldConfig {
|
|
316
|
+
/**
|
|
317
|
+
* Field name from entity type
|
|
318
|
+
* @example "title", "name", "id", "description"
|
|
319
|
+
*/
|
|
320
|
+
name: string;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* GraphQL scalar type
|
|
324
|
+
* @example "String", "Int", "Date", "Datetime", "Boolean", "UUID", "Enum"
|
|
325
|
+
*/
|
|
326
|
+
type: string;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* True if field is non-nullable (ends with `!`)
|
|
330
|
+
* @example true for "title: String!", false for "synopsis: String"
|
|
331
|
+
*/
|
|
332
|
+
isRequired: boolean;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* True if field exists in {Entity}Patch type (can be updated)
|
|
336
|
+
* Check if field appears in the Patch type definition
|
|
337
|
+
* @example true for "description", false for "publishStatus", "createdDate"
|
|
338
|
+
*/
|
|
339
|
+
isUpdatable: boolean;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Validation constraints extracted from field description in Input/Patch types
|
|
343
|
+
*/
|
|
344
|
+
constraints?: {
|
|
345
|
+
/**
|
|
346
|
+
* Minimum length for string fields - parse from @minLength directive
|
|
347
|
+
* @example 3 (from "@minLength(3)")
|
|
348
|
+
*/
|
|
349
|
+
minLength?: number;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Maximum length for string fields - parse from @maxLength directive
|
|
353
|
+
* @example 100 (from "@maxLength(100)")
|
|
354
|
+
*/
|
|
355
|
+
maxLength?: number;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Semantic hint detected from field name - used for custom renderers
|
|
360
|
+
* @example "duration" (for durationInSeconds), "fileSize" (for sizeInBytes)
|
|
361
|
+
*/
|
|
362
|
+
semanticHint?: 'duration' | 'currency' | 'percentage' | 'fileSize';
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Enum type name if field is enum
|
|
366
|
+
* @example "PublishStatus", "MovieImageType"
|
|
367
|
+
*/
|
|
368
|
+
enumType?: string;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* True for Enum fields that are NOT found in the Patch/Input types, meaning they're controlled via mutations
|
|
372
|
+
* @example true for "approvalStatus"
|
|
373
|
+
*/
|
|
374
|
+
isMutationControlled?: boolean;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* TagLike: connection where nodes have simple scalar display field
|
|
379
|
+
* Pattern: `{entity}{AssociationPlural}` → nodes have direct scalar field
|
|
380
|
+
* @example moviesTags { nodes { name } }, moviesCasts { nodes { name } }
|
|
381
|
+
*/
|
|
382
|
+
interface TagLikeAssociation {
|
|
383
|
+
/**
|
|
384
|
+
* Connection field name from entity type
|
|
385
|
+
* @example "moviesTags", "moviesCasts"
|
|
386
|
+
*/
|
|
387
|
+
connectionField: string;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Node type extracted from connection
|
|
391
|
+
* @example "MoviesTag", "MoviesCast"
|
|
392
|
+
*/
|
|
393
|
+
nodeType: string;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* OrderBy type - pattern: `{PascalConnection}OrderBy`
|
|
397
|
+
* @example "MoviesTagsOrderBy", "MoviesCastsOrderBy"
|
|
398
|
+
*/
|
|
399
|
+
orderByType: string;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Display field - look for `name` or `title` in node type
|
|
403
|
+
* @example "name"
|
|
404
|
+
*/
|
|
405
|
+
displayField: string;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Humanized label for UI
|
|
409
|
+
* @example "Tags", "Casts", "Production Countries"
|
|
410
|
+
*/
|
|
411
|
+
label: string;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* ManyToMany: junction connection where nodes have nested relation
|
|
416
|
+
* Pattern: `{entity}{Junction}` → nodes have field pointing to related entity
|
|
417
|
+
* @example moviesMovieGenres { nodes { movieGenres { title } } }
|
|
418
|
+
*/
|
|
419
|
+
interface ManyToManyAssociation {
|
|
420
|
+
/**
|
|
421
|
+
* Connection field name from entity type
|
|
422
|
+
* @example "moviesMovieGenres"
|
|
423
|
+
*/
|
|
424
|
+
connectionField: string;
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Junction type extracted from connection
|
|
428
|
+
* @example "MoviesMovieGenre"
|
|
429
|
+
*/
|
|
430
|
+
junctionType: string;
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Junction OrderBy - pattern: `{PascalConnection}OrderBy`
|
|
434
|
+
* @example "MoviesMovieGenresOrderBy"
|
|
435
|
+
*/
|
|
436
|
+
junctionOrderByType: string;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Related field in junction - find non-ID field pointing to related entity
|
|
440
|
+
* @example "movieGenres" (field in MoviesMovieGenre type)
|
|
441
|
+
*/
|
|
442
|
+
relatedField: string;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Related entity type
|
|
446
|
+
* @example "MovieGenre"
|
|
447
|
+
*/
|
|
448
|
+
relatedType: string;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Related query field - pluralized camelCase of related type
|
|
452
|
+
* @example "movieGenres" (Query field for fetching options)
|
|
453
|
+
*/
|
|
454
|
+
relatedQueryField: string;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Related OrderBy - pattern: `{RelatedPlural}OrderBy` (NO entity prefix)
|
|
458
|
+
* @example "MovieGenresOrderBy" (not MoviesMovieGenresOrderBy)
|
|
459
|
+
*/
|
|
460
|
+
relatedOrderByType: string;
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Display field - look for `title` or `name` in related type
|
|
464
|
+
* @example "title"
|
|
465
|
+
*/
|
|
466
|
+
displayField: string;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Humanized label for UI
|
|
470
|
+
* @example "Genres"
|
|
471
|
+
*/
|
|
472
|
+
label: string;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
interface FieldFeatures {
|
|
476
|
+
/**
|
|
477
|
+
* All the directly defined fields of the entity
|
|
478
|
+
* except the audit fields & association (TagLike, ManyToMany) fields
|
|
479
|
+
*/
|
|
480
|
+
scalars: ScalarFieldConfig[];
|
|
481
|
+
|
|
482
|
+
associations: {
|
|
483
|
+
/**
|
|
484
|
+
* TagLike associations - `1:M` connections with simple scalar display field
|
|
485
|
+
* @example moviesTags, moviesCasts, moviesProductionCountries
|
|
486
|
+
*/
|
|
487
|
+
tagLike: TagLikeAssociation[];
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* ManyToMany associations - `M:N` connections through junction tables
|
|
491
|
+
* @example moviesMovieGenres (Movie ←→ MovieGenre)
|
|
492
|
+
*/
|
|
493
|
+
manyToMany: ManyToManyAssociation[];
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Audit fields - check entity type for these timestamp/user fields
|
|
498
|
+
*/
|
|
499
|
+
audit: {
|
|
500
|
+
/**
|
|
501
|
+
* True if entity has a `createdDate` or a `createdAt` field
|
|
502
|
+
*/
|
|
503
|
+
createdDate: boolean;
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* True if entity has a `createdUser` or a `createdBy` field
|
|
507
|
+
*/
|
|
508
|
+
createdUser: boolean;
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* True if entity has a `updatedDate` or a `updatedAt` field
|
|
512
|
+
*/
|
|
513
|
+
updatedDate: boolean;
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* True if entity has a `updatedUser` or a `updatedBy` field
|
|
517
|
+
*/
|
|
518
|
+
updatedUser: boolean;
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Service metadata - extract from entity type description and service context
|
|
524
|
+
*/
|
|
525
|
+
interface ServiceFeatures {
|
|
526
|
+
/**
|
|
527
|
+
* Service ID - pattern: `{serviceName}-service`
|
|
528
|
+
* @example "media-service", "catalog-service", "channel-service"
|
|
529
|
+
*/
|
|
530
|
+
serviceId: string;
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Permissions - parse from `@permissions` directive in entity type description
|
|
534
|
+
* Format: `"""@permissions: PERM1,PERM2,PERM3"""`
|
|
535
|
+
* @example ["MOVIES_VIEW", "MOVIES_EDIT", "ADMIN"]
|
|
536
|
+
*/
|
|
537
|
+
permissions: string[];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
type EntityFeatures = IdentityFeatures & {
|
|
541
|
+
schema: SchemaNames;
|
|
542
|
+
queries: QueryFeatures & { names: QueryNames };
|
|
543
|
+
mutations: MutationFeatures & { names: MutationNames };
|
|
544
|
+
subscriptions: SubscriptionNames;
|
|
545
|
+
capabilities: CapabilityFeatures;
|
|
546
|
+
fields: FieldFeatures;
|
|
547
|
+
service: ServiceFeatures;
|
|
548
|
+
};
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
## Extraction Process
|
|
552
|
+
|
|
553
|
+
- Use below GQL parsing MCP schema tools to extract entity information from
|
|
554
|
+
GraphQL schema and build the `EntityFeatures` object following the structure
|
|
555
|
+
above.
|
|
556
|
+
- `search_schema`
|
|
557
|
+
- `get_type_definitions`
|
|
558
|
+
- `get_query_fields`
|
|
559
|
+
- `get_mutation_fields`
|
|
560
|
+
- `get_subscription_fields`
|
|
561
|
+
|
|
562
|
+
# Present Features
|
|
563
|
+
|
|
564
|
+
After you have extracted the completed entity features, you MUST print the final
|
|
565
|
+
`EntityFeatures` object so the user is aware of the root of all decisions
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: generate-create-station
|
|
3
|
+
description: |
|
|
4
|
+
Generates a Create station for a Mosaic entity from scratch using
|
|
5
|
+
components from the `@axinom/mosaic-ui` library and GraphQL schema
|
|
6
|
+
introspection.
|
|
7
|
+
|
|
8
|
+
This skill is SELF-CONTAINED with all conventions, naming patterns, code
|
|
9
|
+
structures, and templates defined in its `references`. The skill's templates
|
|
10
|
+
and conventions are the AUTHORITATIVE source - rely on them as the primary
|
|
11
|
+
guide for all generation decisions.
|
|
12
|
+
|
|
13
|
+
Use the `get_skill_references` to retrieve ALL reference
|
|
14
|
+
files mentioned in the steps below BEFORE starting any code generation.
|
|
15
|
+
allowed-tools:
|
|
16
|
+
- search_schema
|
|
17
|
+
- get_type_definitions
|
|
18
|
+
- get_query_fields
|
|
19
|
+
- get_mutation_fields
|
|
20
|
+
- get_subscription_fields
|
|
21
|
+
- list_skills
|
|
22
|
+
- get_skill
|
|
23
|
+
- get_skill_references
|
|
24
|
+
- execute_skill
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Generate Create Station
|
|
28
|
+
|
|
29
|
+
## Input
|
|
30
|
+
|
|
31
|
+
**Entity name** (PascalCase): e.g., "Movie", "Product", "ServiceAccount"
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
|
|
35
|
+
Complete create station with:
|
|
36
|
+
|
|
37
|
+
- Create form component with create mutation and navigation
|
|
38
|
+
- GraphQL create mutation
|
|
39
|
+
- Breadcrumb resolver
|
|
40
|
+
- Route registration
|
|
41
|
+
- Explorer integration (onCreateAction)
|
|
42
|
+
|
|
43
|
+
## Steps
|
|
44
|
+
|
|
45
|
+
### 1. Discover Project Paths → `../_shared/discovery/discover-paths.md`
|
|
46
|
+
|
|
47
|
+
Discover: schema path, apollo client, generated types path, workflows path,
|
|
48
|
+
service name
|
|
49
|
+
|
|
50
|
+
### 2. Extract Entity Features → `../_shared/discovery/extract-entity-features.md`
|
|
51
|
+
|
|
52
|
+
Extract `EntityFeatures` from schema using MCP tools (fields, mutations, schema
|
|
53
|
+
types)
|
|
54
|
+
|
|
55
|
+
**Key for Create:** `schema.input` type contains all input fields with
|
|
56
|
+
`isRequired` property
|
|
57
|
+
|
|
58
|
+
### 3. Generate GraphQL Operations → `refs/templates/graphql-operations.md`
|
|
59
|
+
|
|
60
|
+
Generate `.graphql` file with create mutation returning `id` and `titleField`
|
|
61
|
+
|
|
62
|
+
### 4. Run Codegen → `../_shared/actions/typescript-codegen.md`
|
|
63
|
+
|
|
64
|
+
Generate TypeScript types from GraphQL operations
|
|
65
|
+
|
|
66
|
+
### 5. Generate Create Form Station
|
|
67
|
+
|
|
68
|
+
#### 5.1. Read Field Component Mapping → `../_shared/conventions/field-component-mapping.md`
|
|
69
|
+
|
|
70
|
+
Reference for component selection rules (String → TextField, Int → TextField
|
|
71
|
+
with type="number", etc.)
|
|
72
|
+
|
|
73
|
+
#### 5.2. Read Field Validation Schema → `../_shared/conventions/field-validation-schema.md`
|
|
74
|
+
|
|
75
|
+
Reference for Yup validation patterns (required, maxLength, integer, etc.)
|
|
76
|
+
|
|
77
|
+
#### 5.3. Generate Create Component → `refs/templates/create-form-station.md`
|
|
78
|
+
|
|
79
|
+
Generate `{Entity}Create.tsx` with Create component, validation, mutation,
|
|
80
|
+
navigation, and breadcrumb
|
|
81
|
+
|
|
82
|
+
### 6. Register Station → `refs/finalization/station-registration.md`
|
|
83
|
+
|
|
84
|
+
Register create route and update explorer's `onCreateAction` (if explorer
|
|
85
|
+
exists)
|
|
86
|
+
|
|
87
|
+
### 7. Validate TypeScript → `../_shared/actions/typescript-validation.md`
|
|
88
|
+
|
|
89
|
+
Run `tsc --noEmit` to verify all generated files compile successfully
|
|
90
|
+
|
|
91
|
+
### 8. Print Summary → `../_shared/actions/execution-summary.md`
|
|
92
|
+
|
|
93
|
+
Display execution summary with generated files, routes, fields, TODOs
|