@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.
Files changed (72) hide show
  1. package/README.md +121 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +58 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/logger.d.ts +6 -0
  7. package/dist/logger.d.ts.map +1 -0
  8. package/dist/logger.js +15 -0
  9. package/dist/logger.js.map +1 -0
  10. package/dist/tools/graphql/index.d.ts +3 -0
  11. package/dist/tools/graphql/index.d.ts.map +1 -0
  12. package/dist/tools/graphql/index.js +84 -0
  13. package/dist/tools/graphql/index.js.map +1 -0
  14. package/dist/tools/graphql/tools.d.ts +71 -0
  15. package/dist/tools/graphql/tools.d.ts.map +1 -0
  16. package/dist/tools/graphql/tools.js +187 -0
  17. package/dist/tools/graphql/tools.js.map +1 -0
  18. package/dist/tools/graphql/utils.d.ts +20 -0
  19. package/dist/tools/graphql/utils.d.ts.map +1 -0
  20. package/dist/tools/graphql/utils.js +140 -0
  21. package/dist/tools/graphql/utils.js.map +1 -0
  22. package/dist/tools/skills/index.d.ts +3 -0
  23. package/dist/tools/skills/index.d.ts.map +1 -0
  24. package/dist/tools/skills/index.js +62 -0
  25. package/dist/tools/skills/index.js.map +1 -0
  26. package/dist/tools/skills/tools.d.ts +5 -0
  27. package/dist/tools/skills/tools.d.ts.map +1 -0
  28. package/dist/tools/skills/tools.js +67 -0
  29. package/dist/tools/skills/tools.js.map +1 -0
  30. package/dist/tools/skills/types.d.ts +12 -0
  31. package/dist/tools/skills/types.d.ts.map +1 -0
  32. package/dist/tools/skills/types.js +3 -0
  33. package/dist/tools/skills/types.js.map +1 -0
  34. package/dist/tools/skills/utils.d.ts +11 -0
  35. package/dist/tools/skills/utils.d.ts.map +1 -0
  36. package/dist/tools/skills/utils.js +127 -0
  37. package/dist/tools/skills/utils.js.map +1 -0
  38. package/package.json +40 -0
  39. package/skills/_shared/actions/execution-summary.md +53 -0
  40. package/skills/_shared/actions/typescript-codegen.md +32 -0
  41. package/skills/_shared/actions/typescript-validation.md +32 -0
  42. package/skills/_shared/conventions/field-component-mapping.md +155 -0
  43. package/skills/_shared/conventions/field-validation-schema.md +77 -0
  44. package/skills/_shared/discovery/discover-paths.md +52 -0
  45. package/skills/_shared/discovery/extract-entity-features.md +565 -0
  46. package/skills/generate-create-station/SKILL.md +93 -0
  47. package/skills/generate-create-station/refs/finalization/station-registration.md +163 -0
  48. package/skills/generate-create-station/refs/templates/create-form-station.md +206 -0
  49. package/skills/generate-create-station/refs/templates/graphql-operations.md +56 -0
  50. package/skills/generate-details-station/SKILL.md +125 -0
  51. package/skills/generate-details-station/refs/finalization/explorer-integration.md +242 -0
  52. package/skills/generate-details-station/refs/finalization/station-registration.md +139 -0
  53. package/skills/generate-details-station/refs/templates/actions.md +127 -0
  54. package/skills/generate-details-station/refs/templates/breadcrumb.md +67 -0
  55. package/skills/generate-details-station/refs/templates/details-form-station.md +589 -0
  56. package/skills/generate-details-station/refs/templates/details-wrapper.md +54 -0
  57. package/skills/generate-details-station/refs/templates/form-data-types.md +62 -0
  58. package/skills/generate-details-station/refs/templates/graphql-operations.md +256 -0
  59. package/skills/generate-details-station/refs/templates/managed-integrations/image-management-station.md +322 -0
  60. package/skills/generate-details-station/refs/templates/managed-integrations/video-management-station.md +283 -0
  61. package/skills/generate-explorer-station/SKILL.md +121 -0
  62. package/skills/generate-explorer-station/refs/finalization/station-registration.md +145 -0
  63. package/skills/generate-explorer-station/refs/select-columns-filters.md +63 -0
  64. package/skills/generate-explorer-station/refs/templates/bulk-edit.md +369 -0
  65. package/skills/generate-explorer-station/refs/templates/common/bulk-actions.md +64 -0
  66. package/skills/generate-explorer-station/refs/templates/common/columns.md +131 -0
  67. package/skills/generate-explorer-station/refs/templates/common/data-provider.md +83 -0
  68. package/skills/generate-explorer-station/refs/templates/common/filters.md +220 -0
  69. package/skills/generate-explorer-station/refs/templates/common/inline-actions.md +45 -0
  70. package/skills/generate-explorer-station/refs/templates/common/types.md +28 -0
  71. package/skills/generate-explorer-station/refs/templates/graphql-operations.md +235 -0
  72. 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