@almadar/core 2.14.3 → 3.0.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.
@@ -1,5 +1,5 @@
1
- import { T as TraitEventContract, E as EntityField, a as EntityPersistence, b as EntityRow, O as OrbitalDefinition, c as OrbitalSchema, d as Trait, e as Entity, P as Page } from './schema-BFnZrBhm.js';
2
- export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-CQC8hsaL.js';
1
+ import { T as TraitEventContract, E as EntityField, a as EntityPersistence, b as EntityRow, O as OrbitalDefinition, c as OrbitalSchema, d as Trait, e as Entity, P as Page } from './schema-COvHzxfu.js';
2
+ export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-tUJ7EcaX.js';
3
3
  import 'zod';
4
4
  import '@almadar/patterns';
5
5
 
package/dist/builders.js CHANGED
@@ -1,66 +1,181 @@
1
1
  import { z } from 'zod';
2
2
 
3
- // src/builders/layout-strategy.ts
4
- function hasSequentialChain(wiring) {
5
- if (wiring.length < 2) {
6
- return false;
7
- }
8
- const adjacency = /* @__PURE__ */ new Map();
9
- const allTargets = /* @__PURE__ */ new Set();
10
- for (const entry of wiring) {
11
- let targets = adjacency.get(entry.from);
12
- if (!targets) {
13
- targets = /* @__PURE__ */ new Set();
14
- adjacency.set(entry.from, targets);
15
- }
16
- targets.add(entry.to);
17
- allTargets.add(entry.to);
18
- }
19
- const roots = [];
20
- for (const from of adjacency.keys()) {
21
- if (!allTargets.has(from)) {
22
- roots.push(from);
23
- }
24
- }
25
- const starts = roots.length > 0 ? roots : [...adjacency.keys()];
26
- for (const start of starts) {
27
- let current = start;
28
- let length = 1;
29
- const visited = /* @__PURE__ */ new Set([current]);
30
- while (true) {
31
- const nexts = adjacency.get(current);
32
- if (!nexts || nexts.size === 0) break;
33
- let advanced = false;
34
- for (const next of nexts) {
35
- if (!visited.has(next)) {
36
- visited.add(next);
37
- current = next;
38
- length++;
39
- advanced = true;
40
- break;
41
- }
42
- }
43
- if (!advanced) break;
44
- }
45
- if (length >= 3) {
46
- return true;
47
- }
48
- }
49
- return false;
50
- }
51
- function detectLayoutStrategy(orbitals, eventWiring) {
52
- if (eventWiring && eventWiring.length > 0 && hasSequentialChain(eventWiring)) {
53
- return "wizard-flow";
54
- }
55
- const count = orbitals.length;
56
- if (count <= 1) {
57
- return "single";
58
- }
59
- if (count <= 4) {
60
- return "tabs";
61
- }
62
- return "sidebar";
63
- }
3
+ // src/types/orbital.ts
4
+ var FieldTypeSchema = z.enum([
5
+ "string",
6
+ "number",
7
+ "boolean",
8
+ "date",
9
+ "timestamp",
10
+ "datetime",
11
+ "array",
12
+ "object",
13
+ "enum",
14
+ "relation"
15
+ ]);
16
+ var RelationCardinalitySchema = z.enum([
17
+ "one",
18
+ "many",
19
+ "one-to-many",
20
+ "many-to-one",
21
+ "many-to-many"
22
+ ]);
23
+ var RelationConfigSchema = z.object({
24
+ entity: z.string().min(1, "Target entity is required"),
25
+ field: z.string().optional(),
26
+ cardinality: RelationCardinalitySchema.optional(),
27
+ onDelete: z.enum(["cascade", "nullify", "restrict"]).optional(),
28
+ // Legacy compatibility fields
29
+ foreignKey: z.string().optional(),
30
+ target: z.string().optional(),
31
+ type: RelationCardinalitySchema.optional()
32
+ }).transform((data) => {
33
+ const normalized = {
34
+ entity: data.entity || data.target || "",
35
+ cardinality: data.cardinality || data.type,
36
+ field: data.field,
37
+ onDelete: data.onDelete
38
+ };
39
+ return normalized;
40
+ });
41
+ var FieldFormatSchema = z.enum([
42
+ "email",
43
+ "url",
44
+ "phone",
45
+ "date",
46
+ "datetime",
47
+ "uuid"
48
+ ]);
49
+ var EntityFieldSchema = z.lazy(
50
+ () => z.object({
51
+ name: z.string().min(1, "Field name is required"),
52
+ type: FieldTypeSchema,
53
+ required: z.boolean().optional(),
54
+ default: z.unknown().optional(),
55
+ values: z.array(z.string()).optional(),
56
+ enum: z.array(z.string()).optional(),
57
+ format: FieldFormatSchema.optional(),
58
+ min: z.number().optional(),
59
+ max: z.number().optional(),
60
+ items: EntityFieldSchema.optional(),
61
+ relation: RelationConfigSchema.optional()
62
+ }).refine(
63
+ (field) => field.type !== "relation" || field.relation !== void 0,
64
+ { message: 'Relation config is required when type is "relation"', path: ["relation"] }
65
+ )
66
+ );
67
+ var ENTITY_ROLES = [
68
+ "player",
69
+ "enemy",
70
+ "npc",
71
+ "item",
72
+ "tile",
73
+ "projectile",
74
+ "effect",
75
+ "ui",
76
+ "decoration",
77
+ "vehicle"
78
+ ];
79
+ var EntityRoleSchema = z.enum(ENTITY_ROLES);
80
+ var VISUAL_STYLES = ["pixel", "vector", "hd", "1-bit", "isometric"];
81
+ var VisualStyleSchema = z.enum(VISUAL_STYLES);
82
+ var GAME_TYPES = [
83
+ "platformer",
84
+ "roguelike",
85
+ "top-down",
86
+ "puzzle",
87
+ "racing",
88
+ "card",
89
+ "board",
90
+ "shooter",
91
+ "rpg"
92
+ ];
93
+ var GameTypeSchema = z.enum(GAME_TYPES);
94
+ var AnimationDefSchema = z.object({
95
+ frames: z.union([z.array(z.number()), z.array(z.string())]),
96
+ fps: z.number().positive(),
97
+ loop: z.boolean()
98
+ });
99
+ var SemanticAssetRefSchema = z.object({
100
+ role: EntityRoleSchema,
101
+ category: z.string().min(1),
102
+ animations: z.array(z.string()).optional(),
103
+ style: VisualStyleSchema.optional(),
104
+ variant: z.string().optional()
105
+ });
106
+ z.object({
107
+ basePath: z.string(),
108
+ path: z.string(),
109
+ tiles: z.array(z.number()).optional(),
110
+ tileSize: z.number().positive().optional(),
111
+ files: z.array(z.string()).optional(),
112
+ animations: z.record(AnimationDefSchema).optional()
113
+ });
114
+ var AssetMappingSchema = z.object({
115
+ path: z.string(),
116
+ tiles: z.array(z.number()).optional(),
117
+ tileSize: z.number().positive().optional(),
118
+ files: z.array(z.string()).optional(),
119
+ animations: z.record(AnimationDefSchema).optional()
120
+ });
121
+ z.object({
122
+ gameType: GameTypeSchema,
123
+ style: VisualStyleSchema,
124
+ basePath: z.string(),
125
+ mappings: z.record(AssetMappingSchema)
126
+ });
127
+
128
+ // src/types/entity.ts
129
+ var EntityPersistenceSchema = z.enum([
130
+ "persistent",
131
+ "runtime",
132
+ "singleton",
133
+ "instance",
134
+ "local"
135
+ ]);
136
+ var OrbitalEntitySchema = z.object({
137
+ name: z.string().min(1, "Entity name is required"),
138
+ persistence: EntityPersistenceSchema.default("persistent"),
139
+ collection: z.string().optional(),
140
+ fields: z.array(EntityFieldSchema).min(1, "At least one field is required"),
141
+ instances: z.array(z.record(z.unknown())).optional(),
142
+ timestamps: z.boolean().optional(),
143
+ softDelete: z.boolean().optional(),
144
+ description: z.string().optional(),
145
+ visual_prompt: z.string().optional(),
146
+ assetRef: SemanticAssetRefSchema.optional()
147
+ });
148
+ var EntitySchema = OrbitalEntitySchema;
149
+ var ViewTypeSchema = z.enum([
150
+ "list",
151
+ "detail",
152
+ "create",
153
+ "edit",
154
+ "dashboard",
155
+ "custom"
156
+ ]);
157
+ var PageTraitRefSchema = z.object({
158
+ ref: z.string().min(1, "Trait ref is required"),
159
+ linkedEntity: z.string().optional(),
160
+ config: z.record(z.unknown()).optional()
161
+ });
162
+ z.object({
163
+ name: z.string().min(1, "Page name is required"),
164
+ path: z.string().min(1, "Page path is required").startsWith("/", "Path must start with /"),
165
+ primaryEntity: z.string().min(1, "Primary entity is required"),
166
+ traits: z.array(PageTraitRefSchema).min(1, "Page must have at least one trait"),
167
+ title: z.string().optional()
168
+ }).strict();
169
+ var OrbitalPageSchema = z.object({
170
+ name: z.string().min(1, "Page name is required"),
171
+ path: z.string().min(1, "Page path is required").startsWith("/", "Path must start with /"),
172
+ viewType: ViewTypeSchema.optional(),
173
+ title: z.string().optional(),
174
+ primaryEntity: z.string().optional(),
175
+ traits: z.array(PageTraitRefSchema).optional(),
176
+ isInitial: z.boolean().optional()
177
+ }).strict();
178
+ var PageSchema = OrbitalPageSchema;
64
179
  var UI_SLOTS = [
65
180
  // App slots
66
181
  "main",
@@ -244,6 +359,8 @@ var RequiredFieldSchema = z.object({
244
359
  z.object({
245
360
  ref: z.string().min(1),
246
361
  linkedEntity: z.string().optional(),
362
+ name: z.string().optional(),
363
+ events: z.record(z.string(), z.string()).optional(),
247
364
  config: z.record(z.record(z.unknown())).optional(),
248
365
  appliesTo: z.array(z.string()).optional()
249
366
  });
@@ -262,12 +379,14 @@ var TraitSchema = z.object({
262
379
  listens: z.array(TraitEventListenerSchema).optional(),
263
380
  ui: z.record(z.unknown()).optional()
264
381
  });
265
- z.union([
382
+ var TraitRefSchema = z.union([
266
383
  z.string().min(1),
267
384
  z.object({
268
385
  ref: z.string().min(1),
269
386
  config: z.record(z.unknown()).optional(),
270
- linkedEntity: z.string().optional()
387
+ linkedEntity: z.string().optional(),
388
+ name: z.string().optional(),
389
+ events: z.record(z.string(), z.string()).optional()
271
390
  }),
272
391
  TraitSchema
273
392
  // Allow inline trait definitions
@@ -275,6 +394,403 @@ z.union([
275
394
  function isInlineTrait(traitRef) {
276
395
  return typeof traitRef === "object" && "name" in traitRef && !("ref" in traitRef);
277
396
  }
397
+ z.enum([
398
+ "healthcare",
399
+ "education",
400
+ "finance",
401
+ "ecommerce",
402
+ "real-estate",
403
+ "logistics",
404
+ "hospitality",
405
+ "hr-management",
406
+ "project-management",
407
+ "social",
408
+ "content-management",
409
+ "iot",
410
+ "analytics",
411
+ "game",
412
+ "custom"
413
+ ]);
414
+ var AGENT_DOMAIN_CATEGORIES = [
415
+ "game",
416
+ "business",
417
+ "dashboard",
418
+ "form",
419
+ "content",
420
+ "social",
421
+ "ecommerce",
422
+ "workflow"
423
+ ];
424
+ var AgentDomainCategorySchema = z.enum([...AGENT_DOMAIN_CATEGORIES]);
425
+ z.enum([
426
+ "platformer",
427
+ "shooter",
428
+ "puzzle",
429
+ "rpg",
430
+ "board",
431
+ "racing",
432
+ "fighting",
433
+ "tower-defense",
434
+ "endless-runner",
435
+ "simulation",
436
+ "arcade",
437
+ "adventure"
438
+ ]);
439
+ z.enum(["domain", "system"]);
440
+ z.enum([
441
+ "pending",
442
+ "active",
443
+ "completed",
444
+ "cancelled",
445
+ "error",
446
+ "suspended",
447
+ "blocked",
448
+ "domain_workflow",
449
+ "domain_status",
450
+ "system_loading",
451
+ "system_error",
452
+ "system_idle",
453
+ "system_editing",
454
+ "system_confirming"
455
+ ]);
456
+ z.enum([
457
+ "domain_action",
458
+ "domain_trigger",
459
+ "system_crud",
460
+ "system_navigation",
461
+ "system_form",
462
+ "system_ui"
463
+ ]);
464
+ z.enum([
465
+ "domain_core",
466
+ "domain_supporting",
467
+ "domain_reference",
468
+ "system_user",
469
+ "system_config",
470
+ "system_audit"
471
+ ]);
472
+ var DomainVocabularySchema = z.record(z.string(), z.string()).optional();
473
+ var UserPersonaSchema = z.object({
474
+ name: z.string().min(1),
475
+ role: z.string().optional(),
476
+ device: z.enum(["mobile", "tablet", "desktop"]).optional()
477
+ });
478
+ var DomainContextSchema = z.object({
479
+ request: z.string().min(1, "Original request is required"),
480
+ requestFragment: z.string().optional(),
481
+ category: AgentDomainCategorySchema,
482
+ subDomain: z.string().optional(),
483
+ personas: z.array(UserPersonaSchema).optional(),
484
+ vocabulary: DomainVocabularySchema.optional()
485
+ });
486
+ var UXHintsSchema = z.object({
487
+ flowPattern: z.string().optional(),
488
+ listPattern: z.string().optional(),
489
+ formPattern: z.string().optional(),
490
+ detailPattern: z.string().optional(),
491
+ relatedLinks: z.array(z.lazy(() => RelatedLinkSchema)).optional()
492
+ });
493
+ var RelatedLinkSchema = z.object({
494
+ relation: z.string().min(1),
495
+ label: z.string().min(1),
496
+ targetView: z.enum(["list", "detail"]).optional()
497
+ });
498
+ var SuggestedGuardSchema = z.object({
499
+ id: z.string().min(1),
500
+ description: z.string().min(1),
501
+ appliesTo: z.array(z.string().min(1))
502
+ });
503
+ var DesignPreferencesSchema = z.object({
504
+ style: z.enum(["minimal", "modern", "playful", "data-driven", "immersive"]).optional(),
505
+ primaryColor: z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Must be valid hex color").optional(),
506
+ device: z.enum(["mobile", "tablet", "desktop", "all"]).optional(),
507
+ darkMode: z.boolean().optional(),
508
+ uxHints: UXHintsSchema.optional()
509
+ });
510
+ var ThemeTokensSchema = z.object({
511
+ colors: z.record(z.string(), z.string()).optional(),
512
+ radii: z.record(z.string(), z.string()).optional(),
513
+ spacing: z.record(z.string(), z.string()).optional(),
514
+ typography: z.record(z.string(), z.string()).optional(),
515
+ shadows: z.record(z.string(), z.string()).optional()
516
+ });
517
+ var ThemeVariantSchema = z.object({
518
+ colors: z.record(z.string(), z.string()).optional(),
519
+ radii: z.record(z.string(), z.string()).optional(),
520
+ spacing: z.record(z.string(), z.string()).optional(),
521
+ typography: z.record(z.string(), z.string()).optional(),
522
+ shadows: z.record(z.string(), z.string()).optional()
523
+ });
524
+ var ThemeDefinitionSchema = z.object({
525
+ name: z.string().min(1, "Theme name is required"),
526
+ tokens: ThemeTokensSchema,
527
+ variants: z.record(z.string(), ThemeVariantSchema).optional()
528
+ });
529
+ var ThemeRefStringSchema = z.string().regex(
530
+ /^[A-Z][a-zA-Z0-9]*\.theme$/,
531
+ 'Theme reference must be in format "Alias.theme" (e.g., "Ocean.theme")'
532
+ );
533
+ var ThemeRefSchema = z.union([
534
+ ThemeDefinitionSchema,
535
+ ThemeRefStringSchema
536
+ ]);
537
+ z.record(z.string(), z.record(z.string(), z.string())).optional();
538
+ var ALLOWED_CUSTOM_COMPONENTS = [
539
+ "div",
540
+ "span",
541
+ "button",
542
+ "a",
543
+ "p",
544
+ "h1",
545
+ "h2",
546
+ "h3",
547
+ "h4",
548
+ "h5",
549
+ "h6",
550
+ "header",
551
+ "footer",
552
+ "section",
553
+ "article",
554
+ "nav",
555
+ "main",
556
+ "aside",
557
+ "ul",
558
+ "ol",
559
+ "li",
560
+ "img",
561
+ "label",
562
+ "input",
563
+ "form"
564
+ ];
565
+ var CustomPatternDefinitionSchema = z.object({
566
+ type: z.literal("custom"),
567
+ component: z.enum(ALLOWED_CUSTOM_COMPONENTS),
568
+ className: z.string(),
569
+ slots: z.array(z.string()).optional(),
570
+ props: z.array(z.string()).optional()
571
+ });
572
+ z.record(z.string(), CustomPatternDefinitionSchema).optional();
573
+ var SERVICE_TYPES = ["rest", "socket", "mcp"];
574
+ z.enum(SERVICE_TYPES);
575
+ var RestAuthConfigSchema = z.object({
576
+ type: z.enum(["api-key", "bearer", "basic", "oauth2"]),
577
+ keyName: z.string().optional(),
578
+ location: z.enum(["query", "header"]).optional(),
579
+ secretEnv: z.string().optional()
580
+ });
581
+ var RestServiceDefSchema = z.object({
582
+ name: z.string().min(1, "Service name is required"),
583
+ type: z.literal("rest"),
584
+ description: z.string().optional(),
585
+ baseUrl: z.string().url("Base URL must be a valid URL"),
586
+ headers: z.record(z.string()).optional(),
587
+ auth: RestAuthConfigSchema.optional(),
588
+ timeout: z.number().positive().optional()
589
+ });
590
+ var SocketEventsSchema = z.object({
591
+ inbound: z.array(z.string()),
592
+ outbound: z.array(z.string())
593
+ });
594
+ var SocketServiceDefSchema = z.object({
595
+ name: z.string().min(1, "Service name is required"),
596
+ type: z.literal("socket"),
597
+ description: z.string().optional(),
598
+ url: z.string().url("WebSocket URL must be valid"),
599
+ events: SocketEventsSchema,
600
+ reconnect: z.object({
601
+ enabled: z.boolean(),
602
+ maxAttempts: z.number().positive().optional(),
603
+ delayMs: z.number().positive().optional()
604
+ }).optional()
605
+ });
606
+ var McpServiceDefSchema = z.object({
607
+ name: z.string().min(1, "Service name is required"),
608
+ type: z.literal("mcp"),
609
+ description: z.string().optional(),
610
+ serverPath: z.string().min(1, "Server path is required"),
611
+ capabilities: z.array(z.string()).min(1, "At least one capability is required"),
612
+ env: z.record(z.string()).optional()
613
+ });
614
+ var ServiceDefinitionSchema = z.discriminatedUnion("type", [
615
+ RestServiceDefSchema,
616
+ SocketServiceDefSchema,
617
+ McpServiceDefSchema
618
+ ]);
619
+ var ServiceRefStringSchema = z.string().regex(
620
+ /^[A-Z][a-zA-Z0-9]*\.services\.[a-zA-Z][a-zA-Z0-9]*$/,
621
+ 'Service reference must be in format "Alias.services.ServiceName" (e.g., "Weather.services.openweather")'
622
+ );
623
+ var ServiceRefSchema = z.union([
624
+ ServiceDefinitionSchema,
625
+ ServiceRefStringSchema
626
+ ]);
627
+
628
+ // src/types/orbital.ts
629
+ var UseDeclarationSchema = z.object({
630
+ from: z.string().min(1, "Import source is required"),
631
+ as: z.string().min(1, "Alias is required").regex(
632
+ /^[A-Z][a-zA-Z0-9]*$/,
633
+ 'Alias must be PascalCase (e.g., "Health", "GameCore")'
634
+ )
635
+ });
636
+ function isEntityReference(entity) {
637
+ return typeof entity === "string";
638
+ }
639
+ function isEntityCall(entity) {
640
+ return typeof entity === "object" && entity !== null && "extends" in entity;
641
+ }
642
+ var EntityRefStringSchema = z.string().regex(
643
+ /^[A-Z][a-zA-Z0-9]*\.entity$/,
644
+ 'Entity reference must be in format "Alias.entity" (e.g., "Goblin.entity")'
645
+ );
646
+ var EntityCallSchema = z.object({
647
+ extends: z.string().regex(
648
+ /^[A-Z][a-zA-Z0-9]*\.entity$/,
649
+ 'EntityCall "extends" must be in format "Alias.entity"'
650
+ ),
651
+ name: z.string().optional(),
652
+ fields: z.array(EntityFieldSchema).optional(),
653
+ persistence: EntityPersistenceSchema.optional(),
654
+ collection: z.string().optional()
655
+ });
656
+ var EntityRefSchema = z.union([
657
+ EntitySchema,
658
+ EntityRefStringSchema,
659
+ EntityCallSchema
660
+ ]);
661
+ var PageRefStringSchema = z.string().regex(
662
+ /^[A-Z][a-zA-Z0-9]*\.pages\.[A-Z][a-zA-Z0-9]*$/,
663
+ 'Page reference must be in format "Alias.pages.PageName" (e.g., "User.pages.Profile")'
664
+ );
665
+ var PageRefObjectSchema = z.object({
666
+ ref: PageRefStringSchema,
667
+ path: z.string().startsWith("/").optional(),
668
+ linkedEntity: z.string().optional(),
669
+ traits: z.array(TraitRefSchema).optional()
670
+ });
671
+ var PageRefSchema = z.union([
672
+ PageSchema,
673
+ PageRefStringSchema,
674
+ PageRefObjectSchema
675
+ ]);
676
+ z.string().regex(
677
+ /^([A-Z][a-zA-Z0-9]*\.traits\.)?[A-Z][a-zA-Z0-9]*$/,
678
+ 'Trait reference must be "TraitName" or "Alias.traits.TraitName"'
679
+ );
680
+ function parseEntityRef(ref) {
681
+ const match = ref.match(/^([A-Z][a-zA-Z0-9]*)\.entity$/);
682
+ if (!match) return null;
683
+ return { alias: match[1] };
684
+ }
685
+ z.object({
686
+ event: z.string().min(1),
687
+ triggers: z.string().min(1),
688
+ guard: z.string().optional()
689
+ });
690
+ var EventSourceSchema = z.object({
691
+ trait: z.string().min(1),
692
+ transition: z.string().optional(),
693
+ tick: z.string().optional()
694
+ });
695
+ var ComputedEventContractSchema = z.object({
696
+ event: z.string().min(1),
697
+ originalEvent: z.string().min(1),
698
+ source: EventSourceSchema,
699
+ description: z.string().optional(),
700
+ payload: z.array(EventPayloadFieldSchema).optional()
701
+ });
702
+ var ComputedEventListenerSchema = z.object({
703
+ event: z.string().min(1),
704
+ source: EventSourceSchema,
705
+ triggers: z.string().min(1),
706
+ guard: ExpressionSchema.optional(),
707
+ payloadMapping: z.record(z.string()).optional()
708
+ });
709
+ z.object({
710
+ name: z.string().min(1, "Orbital name is required"),
711
+ description: z.string().optional(),
712
+ visual_prompt: z.string().optional(),
713
+ // Import system
714
+ uses: z.array(UseDeclarationSchema).optional(),
715
+ // Theme & Services
716
+ theme: ThemeRefSchema.optional(),
717
+ services: z.array(ServiceRefSchema).optional(),
718
+ // Components (inline or reference)
719
+ entity: EntityRefSchema,
720
+ traits: z.array(TraitRefSchema),
721
+ pages: z.array(PageRefSchema),
722
+ // Event interface (trait-centric model) - computed by resolver
723
+ emits: z.array(ComputedEventContractSchema).optional(),
724
+ listens: z.array(ComputedEventListenerSchema).optional(),
725
+ // Filter for exposed events (trait-centric model)
726
+ exposes: z.array(z.string()).optional(),
727
+ // Context fields - persisted throughout orbital lifecycle
728
+ domainContext: DomainContextSchema.optional(),
729
+ design: DesignPreferencesSchema.optional(),
730
+ suggestedGuards: z.array(SuggestedGuardSchema).optional()
731
+ });
732
+
733
+ // src/builders/layout-strategy.ts
734
+ function hasSequentialChain(wiring) {
735
+ if (wiring.length < 2) {
736
+ return false;
737
+ }
738
+ const adjacency = /* @__PURE__ */ new Map();
739
+ const allTargets = /* @__PURE__ */ new Set();
740
+ for (const entry of wiring) {
741
+ let targets = adjacency.get(entry.from);
742
+ if (!targets) {
743
+ targets = /* @__PURE__ */ new Set();
744
+ adjacency.set(entry.from, targets);
745
+ }
746
+ targets.add(entry.to);
747
+ allTargets.add(entry.to);
748
+ }
749
+ const roots = [];
750
+ for (const from of adjacency.keys()) {
751
+ if (!allTargets.has(from)) {
752
+ roots.push(from);
753
+ }
754
+ }
755
+ const starts = roots.length > 0 ? roots : [...adjacency.keys()];
756
+ for (const start of starts) {
757
+ let current = start;
758
+ let length = 1;
759
+ const visited = /* @__PURE__ */ new Set([current]);
760
+ while (true) {
761
+ const nexts = adjacency.get(current);
762
+ if (!nexts || nexts.size === 0) break;
763
+ let advanced = false;
764
+ for (const next of nexts) {
765
+ if (!visited.has(next)) {
766
+ visited.add(next);
767
+ current = next;
768
+ length++;
769
+ advanced = true;
770
+ break;
771
+ }
772
+ }
773
+ if (!advanced) break;
774
+ }
775
+ if (length >= 3) {
776
+ return true;
777
+ }
778
+ }
779
+ return false;
780
+ }
781
+ function detectLayoutStrategy(orbitals, eventWiring) {
782
+ if (eventWiring && eventWiring.length > 0 && hasSequentialChain(eventWiring)) {
783
+ return "wizard-flow";
784
+ }
785
+ const count = orbitals.length;
786
+ if (count <= 1) {
787
+ return "single";
788
+ }
789
+ if (count <= 4) {
790
+ return "tabs";
791
+ }
792
+ return "sidebar";
793
+ }
278
794
 
279
795
  // src/builders/event-wiring.ts
280
796
  function findInlineTrait(orbitals, name) {
@@ -420,6 +936,16 @@ function ensureIdField(fields) {
420
936
  function plural(name) {
421
937
  return name + "s";
422
938
  }
939
+ function resolveEntityNameForBuilder(ref) {
940
+ if (isEntityReference(ref)) {
941
+ return parseEntityRef(ref)?.alias ?? ref;
942
+ }
943
+ if (isEntityCall(ref)) {
944
+ if (ref.name) return ref.name;
945
+ return parseEntityRef(ref.extends)?.alias ?? ref.extends;
946
+ }
947
+ return ref.name;
948
+ }
423
949
  function makeEntity(opts) {
424
950
  const fields = ensureIdField(opts.fields);
425
951
  const persistence = opts.persistence ?? "runtime";
@@ -552,7 +1078,7 @@ function pipe(orbitals, events, appName) {
552
1078
  }
553
1079
  }
554
1080
  const pages = cloned.map((o, i) => {
555
- const entityName = typeof o.entity === "string" ? o.entity : o.entity.name;
1081
+ const entityName = resolveEntityNameForBuilder(o.entity);
556
1082
  const traitNames = o.traits.map((t) => t.name);
557
1083
  return {
558
1084
  name: `${entityName}Page`,