@auto-engineer/narrative 1.143.0 → 1.145.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 +34 -0
- package/dist/src/schema.d.ts +4754 -1622
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +21 -10
- package/dist/src/schema.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/schema.specs.ts +76 -91
- package/src/schema.ts +23 -11
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.145.0",
|
|
30
|
+
"@auto-engineer/id": "1.145.0",
|
|
31
|
+
"@auto-engineer/message-bus": "1.145.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.145.0",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsx scripts/build.ts",
|
|
44
44
|
"test": "vitest run --reporter=dot",
|
package/src/schema.specs.ts
CHANGED
|
@@ -3,10 +3,11 @@ import type {
|
|
|
3
3
|
ComponentDefinition,
|
|
4
4
|
Narrative,
|
|
5
5
|
NarrativePlanning,
|
|
6
|
-
RegionEntry,
|
|
7
6
|
SceneClassification,
|
|
8
7
|
SceneRoute,
|
|
9
8
|
UI,
|
|
9
|
+
UIElement,
|
|
10
|
+
UISpec,
|
|
10
11
|
} from './schema';
|
|
11
12
|
import {
|
|
12
13
|
CommandMomentSchema,
|
|
@@ -18,12 +19,13 @@ import {
|
|
|
18
19
|
NarrativePlanningSchema,
|
|
19
20
|
NarrativeSchema,
|
|
20
21
|
QueryMomentSchema,
|
|
21
|
-
RegionEntrySchema,
|
|
22
22
|
SceneClassificationSchema,
|
|
23
23
|
SceneNamesOnlySchema,
|
|
24
24
|
SceneRouteSchema,
|
|
25
25
|
SceneSchema,
|
|
26
|
+
UIElementSchema,
|
|
26
27
|
UISchema,
|
|
28
|
+
UISpecSchema,
|
|
27
29
|
} from './schema';
|
|
28
30
|
|
|
29
31
|
describe('CommandMomentSchema', () => {
|
|
@@ -547,89 +549,70 @@ describe('QueryMomentSchema', () => {
|
|
|
547
549
|
});
|
|
548
550
|
});
|
|
549
551
|
|
|
550
|
-
describe('
|
|
551
|
-
it('should accept
|
|
552
|
-
const result =
|
|
552
|
+
describe('UIElementSchema', () => {
|
|
553
|
+
it('should accept a minimal element with type only', () => {
|
|
554
|
+
const result = UIElementSchema.safeParse({ type: 'Stack' });
|
|
553
555
|
expect(result.success).toBe(true);
|
|
554
|
-
if (result.success) {
|
|
555
|
-
expect(result.data).toEqual({ id: 'hero-1', name: 'HeroBanner' });
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
it('should accept optional slots', () => {
|
|
560
|
-
const result = RegionEntrySchema.safeParse({ id: 'card-1', name: 'Card', slots: { title: 'Hello' } });
|
|
561
|
-
expect(result.success).toBe(true);
|
|
562
|
-
if (result.success) {
|
|
563
|
-
expect(result.data.slots).toEqual({ title: 'Hello' });
|
|
564
|
-
}
|
|
565
556
|
});
|
|
566
557
|
|
|
567
|
-
it('should
|
|
568
|
-
const
|
|
569
|
-
|
|
558
|
+
it('should accept an element with all fields', () => {
|
|
559
|
+
const element = {
|
|
560
|
+
type: 'Heading',
|
|
561
|
+
props: { text: { $state: '/title' }, level: 'h1' },
|
|
562
|
+
children: ['subtitle'],
|
|
563
|
+
visible: { $state: '/showTitle' },
|
|
564
|
+
repeat: { statePath: '/items', key: 'id' },
|
|
565
|
+
watch: { '/count': { action: 'refresh' } },
|
|
566
|
+
};
|
|
567
|
+
expect(UIElementSchema.parse(element)).toEqual(element);
|
|
570
568
|
});
|
|
571
569
|
|
|
572
|
-
it('should
|
|
573
|
-
const
|
|
574
|
-
|
|
570
|
+
it('should accept repeat with object statePath for nested repeats', () => {
|
|
571
|
+
const element = {
|
|
572
|
+
type: 'Stack',
|
|
573
|
+
children: [],
|
|
574
|
+
repeat: { statePath: { $item: 'fields' }, key: 'name' },
|
|
575
|
+
};
|
|
576
|
+
expect(UIElementSchema.parse(element)).toEqual(element);
|
|
575
577
|
});
|
|
576
578
|
});
|
|
577
579
|
|
|
578
|
-
describe('
|
|
579
|
-
it('should accept valid
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
mode: 'as-is',
|
|
590
|
-
regions: { main: [{ id: 'c-1', name: 'List' }] },
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
it('should accept all valid mode values', () => {
|
|
596
|
-
for (const mode of ['as-is', 'modify', 'custom'] as const) {
|
|
597
|
-
const result = UISchema.safeParse({ layoutId: 'l', mode, regions: {} });
|
|
598
|
-
expect(result.success).toBe(true);
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
it('should reject invalid mode', () => {
|
|
603
|
-
const result = UISchema.safeParse({ layoutId: 'l', mode: 'invalid', regions: {} });
|
|
604
|
-
expect(result.success).toBe(false);
|
|
580
|
+
describe('UISpecSchema', () => {
|
|
581
|
+
it('should accept a valid spec with root, elements, and state', () => {
|
|
582
|
+
const spec = {
|
|
583
|
+
root: 'page',
|
|
584
|
+
elements: {
|
|
585
|
+
page: { type: 'Stack', props: { direction: 'vertical' }, children: ['heading'] },
|
|
586
|
+
heading: { type: 'Heading', props: { text: 'Hello' }, children: [] },
|
|
587
|
+
},
|
|
588
|
+
state: { title: 'Hello' },
|
|
589
|
+
};
|
|
590
|
+
expect(UISpecSchema.parse(spec)).toEqual(spec);
|
|
605
591
|
});
|
|
606
592
|
|
|
607
|
-
it('should
|
|
608
|
-
|
|
609
|
-
layoutId: 'l',
|
|
610
|
-
mode: 'modify',
|
|
611
|
-
regions: {},
|
|
612
|
-
customizationNotes: 'Make header sticky',
|
|
613
|
-
});
|
|
614
|
-
expect(result.success).toBe(true);
|
|
615
|
-
if (result.success) {
|
|
616
|
-
expect(result.data.customizationNotes).toBe('Make header sticky');
|
|
617
|
-
}
|
|
593
|
+
it('should reject a spec missing root', () => {
|
|
594
|
+
expect(UISpecSchema.safeParse({ elements: {} }).success).toBe(false);
|
|
618
595
|
});
|
|
619
596
|
|
|
620
|
-
it('should reject missing
|
|
621
|
-
|
|
622
|
-
expect(result.success).toBe(false);
|
|
597
|
+
it('should reject a spec missing elements', () => {
|
|
598
|
+
expect(UISpecSchema.safeParse({ root: 'x' }).success).toBe(false);
|
|
623
599
|
});
|
|
600
|
+
});
|
|
624
601
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
expect(
|
|
602
|
+
describe('UISchema', () => {
|
|
603
|
+
it('should accept an empty object since spec is optional', () => {
|
|
604
|
+
expect(UISchema.parse({})).toEqual({});
|
|
628
605
|
});
|
|
629
606
|
|
|
630
|
-
it('should
|
|
631
|
-
const
|
|
632
|
-
|
|
607
|
+
it('should accept a UI with a spec', () => {
|
|
608
|
+
const ui = {
|
|
609
|
+
spec: {
|
|
610
|
+
root: 'page',
|
|
611
|
+
elements: { page: { type: 'Stack', children: [] } },
|
|
612
|
+
state: { title: 'Dashboard' },
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
expect(UISchema.parse(ui)).toEqual(ui);
|
|
633
616
|
});
|
|
634
617
|
});
|
|
635
618
|
|
|
@@ -663,26 +646,21 @@ describe('ComponentDefinitionSchema', () => {
|
|
|
663
646
|
});
|
|
664
647
|
|
|
665
648
|
describe('DesignSchema ui field', () => {
|
|
666
|
-
it('should accept design with
|
|
667
|
-
const
|
|
649
|
+
it('should accept design with ui containing a spec', () => {
|
|
650
|
+
const design = {
|
|
668
651
|
ui: {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
652
|
+
spec: {
|
|
653
|
+
root: 'page',
|
|
654
|
+
elements: { page: { type: 'Stack', children: [] } },
|
|
655
|
+
state: { title: 'Dashboard' },
|
|
656
|
+
},
|
|
672
657
|
},
|
|
673
|
-
}
|
|
674
|
-
expect(
|
|
675
|
-
if (result.success) {
|
|
676
|
-
expect(result.data.ui?.layoutId).toBe('sidebar');
|
|
677
|
-
}
|
|
658
|
+
};
|
|
659
|
+
expect(DesignSchema.parse(design)).toEqual(design);
|
|
678
660
|
});
|
|
679
661
|
|
|
680
662
|
it('should accept design without ui', () => {
|
|
681
|
-
|
|
682
|
-
expect(result.success).toBe(true);
|
|
683
|
-
if (result.success) {
|
|
684
|
-
expect(result.data.ui).toBeUndefined();
|
|
685
|
-
}
|
|
663
|
+
expect(DesignSchema.parse({})).toEqual({});
|
|
686
664
|
});
|
|
687
665
|
});
|
|
688
666
|
|
|
@@ -731,16 +709,23 @@ describe('modelSchema design.components field', () => {
|
|
|
731
709
|
});
|
|
732
710
|
|
|
733
711
|
describe('exported UI types', () => {
|
|
734
|
-
it('
|
|
735
|
-
const parsed =
|
|
736
|
-
const typed:
|
|
737
|
-
expect(typed).toEqual({
|
|
712
|
+
it('UIElement type matches UIElementSchema inference', () => {
|
|
713
|
+
const parsed = UIElementSchema.parse({ type: 'Stack', children: [] });
|
|
714
|
+
const typed: UIElement = parsed;
|
|
715
|
+
expect(typed).toEqual({ type: 'Stack', children: [] });
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
it('UISpec type matches UISpecSchema inference', () => {
|
|
719
|
+
const spec = { root: 'page', elements: { page: { type: 'Stack', children: [] } } };
|
|
720
|
+
const parsed = UISpecSchema.parse(spec);
|
|
721
|
+
const typed: UISpec = parsed;
|
|
722
|
+
expect(typed).toEqual(spec);
|
|
738
723
|
});
|
|
739
724
|
|
|
740
725
|
it('UI type matches UISchema inference', () => {
|
|
741
|
-
const parsed = UISchema.parse({
|
|
726
|
+
const parsed = UISchema.parse({});
|
|
742
727
|
const typed: UI = parsed;
|
|
743
|
-
expect(typed).toEqual({
|
|
728
|
+
expect(typed).toEqual({});
|
|
744
729
|
});
|
|
745
730
|
|
|
746
731
|
it('ComponentDefinition type matches ComponentDefinitionSchema inference', () => {
|
|
@@ -753,6 +738,6 @@ describe('exported UI types', () => {
|
|
|
753
738
|
template: '<button/>',
|
|
754
739
|
});
|
|
755
740
|
const typed: ComponentDefinition = parsed;
|
|
756
|
-
expect(typed
|
|
741
|
+
expect(typed).toEqual(parsed);
|
|
757
742
|
});
|
|
758
743
|
});
|
package/src/schema.ts
CHANGED
|
@@ -218,20 +218,32 @@ export const ImageAssetSchema = z
|
|
|
218
218
|
})
|
|
219
219
|
.describe('Image asset with optional generation metadata');
|
|
220
220
|
|
|
221
|
-
const
|
|
221
|
+
export const UIElementSchema = z
|
|
222
|
+
.object({
|
|
223
|
+
type: z.string(),
|
|
224
|
+
props: z.record(z.unknown()).optional(),
|
|
225
|
+
children: z.array(z.string()).optional(),
|
|
226
|
+
visible: z.unknown().optional(),
|
|
227
|
+
repeat: z
|
|
228
|
+
.object({ statePath: z.union([z.string(), z.record(z.unknown())]) })
|
|
229
|
+
.passthrough()
|
|
230
|
+
.optional(),
|
|
231
|
+
watch: z.record(z.unknown()).optional(),
|
|
232
|
+
})
|
|
233
|
+
.passthrough()
|
|
234
|
+
.describe('Single UI element in a UI spec');
|
|
235
|
+
|
|
236
|
+
export const UISpecSchema = z
|
|
222
237
|
.object({
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
root: z.string(),
|
|
239
|
+
elements: z.record(UIElementSchema),
|
|
240
|
+
state: z.record(z.unknown()).optional(),
|
|
226
241
|
})
|
|
227
|
-
.describe('
|
|
242
|
+
.describe('Flat element-map UI specification');
|
|
228
243
|
|
|
229
244
|
const UISchema = z
|
|
230
245
|
.object({
|
|
231
|
-
|
|
232
|
-
mode: z.enum(['as-is', 'modify', 'custom']),
|
|
233
|
-
regions: z.record(z.array(RegionEntrySchema)),
|
|
234
|
-
customizationNotes: z.string().optional(),
|
|
246
|
+
spec: UISpecSchema.optional().describe('The rendered UI spec — source of truth for rendering'),
|
|
235
247
|
})
|
|
236
248
|
.describe('UI composition for a moment');
|
|
237
249
|
|
|
@@ -584,7 +596,6 @@ export {
|
|
|
584
596
|
StepErrorSchema,
|
|
585
597
|
StepWithDocStringSchema,
|
|
586
598
|
StepWithErrorSchema,
|
|
587
|
-
RegionEntrySchema,
|
|
588
599
|
UISchema,
|
|
589
600
|
ComponentDefinitionSchema,
|
|
590
601
|
};
|
|
@@ -613,6 +624,7 @@ export type SceneRoute = z.infer<typeof SceneRouteSchema>;
|
|
|
613
624
|
export type NarrativePlanning = z.infer<typeof NarrativePlanningSchema>;
|
|
614
625
|
export type ImageAsset = z.infer<typeof ImageAssetSchema>;
|
|
615
626
|
export type Design = z.infer<typeof DesignSchema>;
|
|
616
|
-
export type
|
|
627
|
+
export type UIElement = z.infer<typeof UIElementSchema>;
|
|
628
|
+
export type UISpec = z.infer<typeof UISpecSchema>;
|
|
617
629
|
export type UI = z.infer<typeof UISchema>;
|
|
618
630
|
export type ComponentDefinition = z.infer<typeof ComponentDefinitionSchema>;
|