@auto-engineer/narrative 1.131.0 → 1.135.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +5 -5
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +155 -0
- package/dist/src/schema.d.ts +2117 -1
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +32 -2
- package/dist/src/schema.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/schema.specs.ts +222 -1
- package/src/schema.ts +41 -1
package/package.json
CHANGED
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"typescript": "^5.9.2",
|
|
27
27
|
"zod": "^3.22.4",
|
|
28
28
|
"zod-to-json-schema": "^3.22.3",
|
|
29
|
-
"@auto-engineer/file-store": "1.
|
|
30
|
-
"@auto-engineer/id": "1.
|
|
31
|
-
"@auto-engineer/message-bus": "1.
|
|
29
|
+
"@auto-engineer/file-store": "1.135.0",
|
|
30
|
+
"@auto-engineer/id": "1.135.0",
|
|
31
|
+
"@auto-engineer/message-bus": "1.135.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^20.0.0",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"version": "1.
|
|
41
|
+
"version": "1.135.0",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsx scripts/build.ts",
|
|
44
44
|
"test": "vitest run --reporter=dot",
|
package/src/schema.specs.ts
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ComponentDefinition,
|
|
4
|
+
Journey,
|
|
5
|
+
JourneyPlanning,
|
|
6
|
+
RegionEntry,
|
|
7
|
+
SceneClassification,
|
|
8
|
+
SceneRoute,
|
|
9
|
+
UI,
|
|
10
|
+
} from './schema';
|
|
3
11
|
import {
|
|
4
12
|
CommandSliceSchema,
|
|
13
|
+
ComponentDefinitionSchema,
|
|
5
14
|
DataSchema,
|
|
6
15
|
DataTargetSchema,
|
|
16
|
+
DesignSchema,
|
|
7
17
|
JourneyPlanningSchema,
|
|
8
18
|
JourneySchema,
|
|
9
19
|
modelSchema,
|
|
10
20
|
NarrativeNamesOnlySchema,
|
|
11
21
|
NarrativeSchema,
|
|
12
22
|
QuerySliceSchema,
|
|
23
|
+
RegionEntrySchema,
|
|
13
24
|
SceneClassificationSchema,
|
|
14
25
|
SceneRouteSchema,
|
|
26
|
+
UISchema,
|
|
15
27
|
} from './schema';
|
|
16
28
|
|
|
17
29
|
describe('CommandSliceSchema', () => {
|
|
@@ -527,3 +539,212 @@ describe('QuerySliceSchema', () => {
|
|
|
527
539
|
}
|
|
528
540
|
});
|
|
529
541
|
});
|
|
542
|
+
|
|
543
|
+
describe('RegionEntrySchema', () => {
|
|
544
|
+
it('should accept valid region entry with required fields', () => {
|
|
545
|
+
const result = RegionEntrySchema.safeParse({ id: 'hero-1', name: 'HeroBanner' });
|
|
546
|
+
expect(result.success).toBe(true);
|
|
547
|
+
if (result.success) {
|
|
548
|
+
expect(result.data).toEqual({ id: 'hero-1', name: 'HeroBanner' });
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should accept optional slots', () => {
|
|
553
|
+
const result = RegionEntrySchema.safeParse({ id: 'card-1', name: 'Card', slots: { title: 'Hello' } });
|
|
554
|
+
expect(result.success).toBe(true);
|
|
555
|
+
if (result.success) {
|
|
556
|
+
expect(result.data.slots).toEqual({ title: 'Hello' });
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('should reject missing id', () => {
|
|
561
|
+
const result = RegionEntrySchema.safeParse({ name: 'Card' });
|
|
562
|
+
expect(result.success).toBe(false);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('should reject missing name', () => {
|
|
566
|
+
const result = RegionEntrySchema.safeParse({ id: 'card-1' });
|
|
567
|
+
expect(result.success).toBe(false);
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
describe('UISchema', () => {
|
|
572
|
+
it('should accept valid UI with required fields', () => {
|
|
573
|
+
const result = UISchema.safeParse({
|
|
574
|
+
layoutId: 'two-column',
|
|
575
|
+
mode: 'as-is',
|
|
576
|
+
regions: { main: [{ id: 'c-1', name: 'List' }] },
|
|
577
|
+
});
|
|
578
|
+
expect(result.success).toBe(true);
|
|
579
|
+
if (result.success) {
|
|
580
|
+
expect(result.data).toEqual({
|
|
581
|
+
layoutId: 'two-column',
|
|
582
|
+
mode: 'as-is',
|
|
583
|
+
regions: { main: [{ id: 'c-1', name: 'List' }] },
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it('should accept all valid mode values', () => {
|
|
589
|
+
for (const mode of ['as-is', 'modify', 'custom'] as const) {
|
|
590
|
+
const result = UISchema.safeParse({ layoutId: 'l', mode, regions: {} });
|
|
591
|
+
expect(result.success).toBe(true);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('should reject invalid mode', () => {
|
|
596
|
+
const result = UISchema.safeParse({ layoutId: 'l', mode: 'invalid', regions: {} });
|
|
597
|
+
expect(result.success).toBe(false);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it('should accept optional customizationNotes', () => {
|
|
601
|
+
const result = UISchema.safeParse({
|
|
602
|
+
layoutId: 'l',
|
|
603
|
+
mode: 'modify',
|
|
604
|
+
regions: {},
|
|
605
|
+
customizationNotes: 'Make header sticky',
|
|
606
|
+
});
|
|
607
|
+
expect(result.success).toBe(true);
|
|
608
|
+
if (result.success) {
|
|
609
|
+
expect(result.data.customizationNotes).toBe('Make header sticky');
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it('should reject missing layoutId', () => {
|
|
614
|
+
const result = UISchema.safeParse({ mode: 'as-is', regions: {} });
|
|
615
|
+
expect(result.success).toBe(false);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it('should reject missing mode', () => {
|
|
619
|
+
const result = UISchema.safeParse({ layoutId: 'l', regions: {} });
|
|
620
|
+
expect(result.success).toBe(false);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it('should reject missing regions', () => {
|
|
624
|
+
const result = UISchema.safeParse({ layoutId: 'l', mode: 'as-is' });
|
|
625
|
+
expect(result.success).toBe(false);
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe('ComponentDefinitionSchema', () => {
|
|
630
|
+
it('should accept valid component definition', () => {
|
|
631
|
+
const result = ComponentDefinitionSchema.safeParse({
|
|
632
|
+
id: 'comp-1',
|
|
633
|
+
name: 'PriceTag',
|
|
634
|
+
category: 'commerce',
|
|
635
|
+
description: 'Displays a price',
|
|
636
|
+
slots: { price: { type: 'number' } },
|
|
637
|
+
template: '<span>{{price}}</span>',
|
|
638
|
+
});
|
|
639
|
+
expect(result.success).toBe(true);
|
|
640
|
+
if (result.success) {
|
|
641
|
+
expect(result.data).toEqual({
|
|
642
|
+
id: 'comp-1',
|
|
643
|
+
name: 'PriceTag',
|
|
644
|
+
category: 'commerce',
|
|
645
|
+
description: 'Displays a price',
|
|
646
|
+
slots: { price: { type: 'number' } },
|
|
647
|
+
template: '<span>{{price}}</span>',
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('should reject missing required fields', () => {
|
|
653
|
+
const result = ComponentDefinitionSchema.safeParse({ id: 'comp-1', name: 'PriceTag' });
|
|
654
|
+
expect(result.success).toBe(false);
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
describe('DesignSchema ui field', () => {
|
|
659
|
+
it('should accept design with optional ui', () => {
|
|
660
|
+
const result = DesignSchema.safeParse({
|
|
661
|
+
ui: {
|
|
662
|
+
layoutId: 'sidebar',
|
|
663
|
+
mode: 'as-is',
|
|
664
|
+
regions: { sidebar: [{ id: 'nav', name: 'NavMenu' }] },
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
expect(result.success).toBe(true);
|
|
668
|
+
if (result.success) {
|
|
669
|
+
expect(result.data.ui?.layoutId).toBe('sidebar');
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it('should accept design without ui', () => {
|
|
674
|
+
const result = DesignSchema.safeParse({});
|
|
675
|
+
expect(result.success).toBe(true);
|
|
676
|
+
if (result.success) {
|
|
677
|
+
expect(result.data.ui).toBeUndefined();
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
describe('modelSchema design.components field', () => {
|
|
683
|
+
const minimalModel = {
|
|
684
|
+
variant: 'specs' as const,
|
|
685
|
+
narratives: [],
|
|
686
|
+
messages: [],
|
|
687
|
+
modules: [],
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
it('should accept model with design.components', () => {
|
|
691
|
+
const result = modelSchema.safeParse({
|
|
692
|
+
...minimalModel,
|
|
693
|
+
design: {
|
|
694
|
+
components: [
|
|
695
|
+
{
|
|
696
|
+
id: 'comp-1',
|
|
697
|
+
name: 'PriceTag',
|
|
698
|
+
category: 'commerce',
|
|
699
|
+
description: 'Displays a price',
|
|
700
|
+
slots: { price: { type: 'number' } },
|
|
701
|
+
template: '<span>{{price}}</span>',
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
},
|
|
705
|
+
});
|
|
706
|
+
expect(result.success).toBe(true);
|
|
707
|
+
if (result.success) {
|
|
708
|
+
expect(result.data.design?.components).toHaveLength(1);
|
|
709
|
+
expect(result.data.design?.components?.[0].name).toBe('PriceTag');
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it('should accept model design without components', () => {
|
|
714
|
+
const result = modelSchema.safeParse({
|
|
715
|
+
...minimalModel,
|
|
716
|
+
design: {},
|
|
717
|
+
});
|
|
718
|
+
expect(result.success).toBe(true);
|
|
719
|
+
if (result.success) {
|
|
720
|
+
expect(result.data.design?.components).toBeUndefined();
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
describe('exported UI types', () => {
|
|
726
|
+
it('RegionEntry type matches RegionEntrySchema inference', () => {
|
|
727
|
+
const parsed = RegionEntrySchema.parse({ id: 'r-1', name: 'Header' });
|
|
728
|
+
const typed: RegionEntry = parsed;
|
|
729
|
+
expect(typed).toEqual({ id: 'r-1', name: 'Header' });
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
it('UI type matches UISchema inference', () => {
|
|
733
|
+
const parsed = UISchema.parse({ layoutId: 'l', mode: 'as-is', regions: {} });
|
|
734
|
+
const typed: UI = parsed;
|
|
735
|
+
expect(typed).toEqual({ layoutId: 'l', mode: 'as-is', regions: {} });
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
it('ComponentDefinition type matches ComponentDefinitionSchema inference', () => {
|
|
739
|
+
const parsed = ComponentDefinitionSchema.parse({
|
|
740
|
+
id: 'c-1',
|
|
741
|
+
name: 'Btn',
|
|
742
|
+
category: 'ui',
|
|
743
|
+
description: 'A button',
|
|
744
|
+
slots: {},
|
|
745
|
+
template: '<button/>',
|
|
746
|
+
});
|
|
747
|
+
const typed: ComponentDefinition = parsed;
|
|
748
|
+
expect(typed.name).toBe('Btn');
|
|
749
|
+
});
|
|
750
|
+
});
|
package/src/schema.ts
CHANGED
|
@@ -207,6 +207,7 @@ export const MappingEntrySchema = z
|
|
|
207
207
|
.object({
|
|
208
208
|
source: MappingFieldRefSchema.describe('Source field reference'),
|
|
209
209
|
target: MappingFieldRefSchema.describe('Target field reference'),
|
|
210
|
+
operator: z.enum(['eq', 'ne', 'gt', 'gte', 'lt', 'lte']).optional(),
|
|
210
211
|
})
|
|
211
212
|
.describe('Mapping entry linking a source field to a target field');
|
|
212
213
|
|
|
@@ -217,10 +218,39 @@ export const ImageAssetSchema = z
|
|
|
217
218
|
})
|
|
218
219
|
.describe('Image asset with optional generation metadata');
|
|
219
220
|
|
|
221
|
+
const RegionEntrySchema = z
|
|
222
|
+
.object({
|
|
223
|
+
id: z.string(),
|
|
224
|
+
name: z.string(),
|
|
225
|
+
slots: z.record(z.unknown()).optional(),
|
|
226
|
+
})
|
|
227
|
+
.describe('Component placed in a layout region');
|
|
228
|
+
|
|
229
|
+
const UISchema = z
|
|
230
|
+
.object({
|
|
231
|
+
layoutId: z.string(),
|
|
232
|
+
mode: z.enum(['as-is', 'modify', 'custom']),
|
|
233
|
+
regions: z.record(z.array(RegionEntrySchema)),
|
|
234
|
+
customizationNotes: z.string().optional(),
|
|
235
|
+
})
|
|
236
|
+
.describe('UI composition for a slice');
|
|
237
|
+
|
|
238
|
+
const ComponentDefinitionSchema = z
|
|
239
|
+
.object({
|
|
240
|
+
id: z.string(),
|
|
241
|
+
name: z.string(),
|
|
242
|
+
category: z.string(),
|
|
243
|
+
description: z.string(),
|
|
244
|
+
slots: z.record(z.unknown()),
|
|
245
|
+
template: z.string(),
|
|
246
|
+
})
|
|
247
|
+
.describe('Custom reusable component definition');
|
|
248
|
+
|
|
220
249
|
export const DesignSchema = z
|
|
221
250
|
.object({
|
|
222
251
|
imageAsset: ImageAssetSchema.optional().describe('Primary image asset for this entity'),
|
|
223
252
|
metadata: z.record(z.unknown()).optional().describe('Flexible design metadata'),
|
|
253
|
+
ui: UISchema.optional().describe('UI composition for this entity'),
|
|
224
254
|
})
|
|
225
255
|
.describe('Design fields for visual representation');
|
|
226
256
|
|
|
@@ -512,6 +542,10 @@ export const ClientServerNamesSchema = z
|
|
|
512
542
|
})
|
|
513
543
|
.describe('System with client/server descriptions for behavior planning');
|
|
514
544
|
|
|
545
|
+
const ModelDesignSchema = DesignSchema.extend({
|
|
546
|
+
components: z.array(ComponentDefinitionSchema).optional().describe('Custom reusable component definitions'),
|
|
547
|
+
}).describe('Model-level design fields with component definitions');
|
|
548
|
+
|
|
515
549
|
export const modelSchema = z
|
|
516
550
|
.object({
|
|
517
551
|
variant: z.literal('specs').describe('Full specification with all details'),
|
|
@@ -520,7 +554,7 @@ export const modelSchema = z
|
|
|
520
554
|
integrations: z.array(IntegrationSchema).optional(),
|
|
521
555
|
modules: z.array(ModuleSchema).describe('Modules for type ownership and file grouping'),
|
|
522
556
|
journeys: z.array(JourneySchema).optional(),
|
|
523
|
-
design:
|
|
557
|
+
design: ModelDesignSchema.optional().describe('Design fields for visual representation'),
|
|
524
558
|
})
|
|
525
559
|
.describe('Complete system specification with all implementation details');
|
|
526
560
|
|
|
@@ -550,6 +584,9 @@ export {
|
|
|
550
584
|
StepErrorSchema,
|
|
551
585
|
StepWithDocStringSchema,
|
|
552
586
|
StepWithErrorSchema,
|
|
587
|
+
RegionEntrySchema,
|
|
588
|
+
UISchema,
|
|
589
|
+
ComponentDefinitionSchema,
|
|
553
590
|
};
|
|
554
591
|
|
|
555
592
|
export type Model = z.infer<typeof modelSchema>;
|
|
@@ -576,3 +613,6 @@ export type SceneRoute = z.infer<typeof SceneRouteSchema>;
|
|
|
576
613
|
export type JourneyPlanning = z.infer<typeof JourneyPlanningSchema>;
|
|
577
614
|
export type ImageAsset = z.infer<typeof ImageAssetSchema>;
|
|
578
615
|
export type Design = z.infer<typeof DesignSchema>;
|
|
616
|
+
export type RegionEntry = z.infer<typeof RegionEntrySchema>;
|
|
617
|
+
export type UI = z.infer<typeof UISchema>;
|
|
618
|
+
export type ComponentDefinition = z.infer<typeof ComponentDefinitionSchema>;
|