@almadar/skills 1.1.3 → 1.2.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/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { join } from 'path';
3
3
  import { generateBehaviorsDocs, getAllBehaviors, generateModulesDocs, getAllStdOperators } from '@almadar/std';
4
4
  import { OPERATORS, UI_SLOTS, PATTERN_TYPES, ViewTypeSchema } from '@almadar/core/types';
5
5
  import { getPatternPropsCompact, getPatternActionsRef, getAllPatternTypes } from '@almadar/patterns';
6
+ import { BINDING_DOCS, CORE_BINDINGS } from '@almadar/core';
6
7
 
7
8
  // src/generators/utils.ts
8
9
  function formatFrontmatter(fm) {
@@ -204,7 +205,7 @@ Trait State Machine \u2192 render-ui \u2192 UI Component \u2192 User Action \u21
204
205
  | **One trait per slot** | Each slot (main, modal, drawer) owned by ONE trait |
205
206
  | **INIT renders UI** | Every trait needs INIT self-loop to render initial UI |
206
207
  | **One page per entity** | Use trait's render-ui for create/edit/view, not separate pages |
207
- | **form-section has onSubmit** | Connects form to trait events |
208
+ | **form-section has submitEvent** | Connects form to trait events (NOT onSubmit!) |
208
209
  | **std/* are templates** | Guide LLM generation, not runtime code |
209
210
 
210
211
  ### Slot Ownership
@@ -215,7 +216,7 @@ Trait State Machine \u2192 render-ui \u2192 UI Component \u2192 User Action \u21
215
216
  \u2502 TaskManagement trait OWNS: \u2502
216
217
  \u2502 \u2022 main \u2192 entity-table, page-header \u2502
217
218
  \u2502 \u2022 modal \u2192 form-section (create/edit) \u2502
218
- \u2502 \u2022 drawer \u2192 entity-detail (view) \u2502
219
+ \u2502 \u2022 drawer \u2192 detail-panel (view) \u2502
219
220
  \u2502 \u2502
220
221
  \u2502 NO other trait should render to these slots \u2502
221
222
  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
@@ -273,6 +274,7 @@ function getCriticalErrors() {
273
274
  ### 1. INIT Transition Required (CRITICAL)
274
275
 
275
276
  Every trait MUST have an INIT self-loop transition. The runtime fires \`INIT\` when page loads.
277
+ The INIT render-ui MUST be a **single composed stack**, not flat calls:
276
278
 
277
279
  \`\`\`json
278
280
  {
@@ -280,8 +282,19 @@ Every trait MUST have an INIT self-loop transition. The runtime fires \`INIT\` w
280
282
  "to": "Browsing",
281
283
  "event": "INIT",
282
284
  "effects": [
283
- ["render-ui", "main", { "type": "page-header", ... }],
284
- ["render-ui", "main", { "type": "entity-table", ... }]
285
+ ["render-ui", "main", {
286
+ "type": "stack", "direction": "vertical", "gap": "lg",
287
+ "children": [
288
+ { "type": "stack", "direction": "horizontal", "justify": "between", "align": "center",
289
+ "children": [
290
+ { "type": "typography", "variant": "h1", "text": "Title" },
291
+ { "type": "button", "label": "Create", "event": "CREATE", "variant": "primary" }
292
+ ]
293
+ },
294
+ { "type": "entity-table", "entity": "EntityName", "columns": ["..."], "searchable": true,
295
+ "itemActions": [{ "label": "View", "event": "VIEW" }] }
296
+ ]
297
+ }]
285
298
  ]
286
299
  }
287
300
  \`\`\`
@@ -377,10 +390,11 @@ WRONG: Two traits both render to "main" on page load
377
390
  CORRECT: ONE trait owns each slot
378
391
  \`\`\`
379
392
 
380
- ### 9. Missing onSubmit in form-section
393
+ ### 9. Missing submitEvent in form-section
381
394
  \`\`\`
382
395
  WRONG: { "type": "form-section", "entity": "Task" }
383
- CORRECT: { "type": "form-section", "entity": "Task", "onSubmit": "SAVE" }
396
+ ALSO WRONG: { "type": "form-section", "entity": "Task", "onSubmit": "SAVE" }
397
+ CORRECT: { "type": "form-section", "entity": "Task", "submitEvent": "SAVE", "cancelEvent": "CANCEL" }
384
398
  \`\`\`
385
399
 
386
400
  ### 10. Duplicate Transitions (Same from+event)
@@ -404,7 +418,7 @@ CORRECT: { "pages": [{ "traits": [...] }] } - UI comes from render-ui effects
404
418
  ### 13. Using form-actions Pattern (DOES NOT EXIST!)
405
419
  \`\`\`
406
420
  WRONG: ["render-ui", "main", { "type": "form-actions", "actions": [...] }]
407
- CORRECT: Use form-section with onSubmit/onCancel props
421
+ CORRECT: Use form-section with submitEvent/cancelEvent props
408
422
  \`\`\`
409
423
  Actions are INSIDE patterns, not separate patterns.
410
424
 
@@ -453,7 +467,7 @@ function getValidationHintsSection() {
453
467
  | ORB_P_MISSING_TRAITS | Add \`traits\` array to page with at least one trait ref |
454
468
  | ORB_E_INVALID_FIELD_TYPE | Use valid type: string, number, boolean, date, enum, relation. NOT entity names! |
455
469
  | ORB_INIT_MISSING | Add INIT self-loop transition with render-ui effects |
456
- | ORB_FORM_SUBMIT | Add onSubmit event name to form-section pattern |
470
+ | ORB_FORM_SUBMIT | Add submitEvent and cancelEvent to form-section pattern |
457
471
  | ORB_DUPE_TRANS | Add guards to differentiate same-event transitions |
458
472
  | ORB_SLOT_CONTENTION | Merge traits or use different slots |
459
473
  | ORB_DUPE_PAGE_TRAITS | Remove duplicate trait references from page |
@@ -743,145 +757,461 @@ Orbitals communicate via events:
743
757
  - Add relatedLinks for navigation between related records
744
758
  `;
745
759
  }
760
+ function getBindingsGuide() {
761
+ const lines = [
762
+ "## Valid Binding References",
763
+ "",
764
+ "Bindings reference runtime values using `@root.path` syntax:",
765
+ "",
766
+ "| Binding | Description | Example |",
767
+ "|---------|-------------|---------|"
768
+ ];
769
+ for (const [bindingKey, docs] of Object.entries(BINDING_DOCS)) {
770
+ const example = docs.examples[0] || `@${bindingKey}`;
771
+ lines.push(`| \`@${bindingKey}\` | ${docs.description} | \`${example}\` |`);
772
+ }
773
+ lines.push(
774
+ "",
775
+ "### Binding Rules",
776
+ "",
777
+ "- `@entity.field` - Access entity fields (e.g., `@entity.status`, `@entity.count`)",
778
+ "- `@payload.field` - Access event payload data (read-only)",
779
+ "- `@state` - Current state name (no path)",
780
+ "- `@now` - Current timestamp (no path)",
781
+ "- `@config.field` - Trait configuration values",
782
+ "",
783
+ "### Common Mistakes",
784
+ "",
785
+ "| \u274C Invalid | \u2705 Correct |",
786
+ "|------------|------------|",
787
+ '| `@count` | Use `stats` pattern or static text (e.g., `"Total Tasks"`) |',
788
+ "| `@count:status=pending` | Use filtered entity-table or static labels |",
789
+ "| `@entity.task.title` | `@entity.title` (entity type is implicit) |",
790
+ "| `@payload.field` in `set` effect | `@entity.field` (set modifies entity only) |",
791
+ ""
792
+ );
793
+ return lines.join("\n");
794
+ }
795
+ function getBindingsCompact() {
796
+ const validBindings = CORE_BINDINGS.map((b) => `@${b}`).join(", ");
797
+ return `Valid bindings: ${validBindings}`;
798
+ }
799
+ function getBindingContextRules() {
800
+ return `
801
+ ## Binding Context Rules
802
+
803
+ | Context | Allowed Bindings | Notes |
804
+ |---------|-----------------|-------|
805
+ | Guards | @entity, @payload, @state, @now | Read-only conditions |
806
+ | Effects | @entity, @payload, @state, @now | @entity can be modified via set |
807
+ | Ticks | @entity, @state, @now | No payload (no event) |
808
+ | Render-UI | @entity, @payload, @state, @config | Display values only |
809
+
810
+ **Critical Rule:** The ".set" effect ONLY modifies @entity fields.
811
+ `.trim();
812
+ }
813
+
814
+ // src/prompts/skill-sections/pattern-design-guide.ts
746
815
  function getRenderUIDesignGuide() {
747
- return `## Render-UI Design Guide
816
+ return `## Render-UI Atomic Composition Guide (v5.0)
748
817
 
749
- ### Syntax
750
- \`["render-ui", slot, { "type": pattern, ...props }]\`
751
- Clear slot: \`["render-ui", "modal", null]\`
818
+ ### The Five Rules of Sophisticated Composition (MANDATORY)
819
+
820
+ Every render-ui effect MUST satisfy ALL five rules:
821
+
822
+ | Rule | Requirement | Validation |
823
+ |------|-------------|------------|
824
+ | **1** | **Single Render-UI** per transition | One render-ui effect only |
825
+ | **2** | **Three Atomic Levels** | Atoms (2+) + Molecules (1+) + Organisms (1+) |
826
+ | **3** | **Layout Wrapper** | Root must be stack/box/container/grid |
827
+ | **4** | **Theme Variables** | ALL visual props use CSS vars |
828
+ | **5** | **Template Quality** | Match CrudTemplate/ListTemplate sophistication |
752
829
 
753
- ### Slot Strategy
754
- | Slot | Use For | Composable? |
755
- |------|---------|-------------|
756
- | \`main\` | Primary content | **YES** \u2014 stack multiple render-ui calls |
757
- | \`modal\` | Forms (create/edit), confirmations | One at a time |
758
- | \`drawer\` | Detail views, quick edits | One at a time |
759
- | \`sidebar\` | Navigation, persistent filters | One at a time |
760
- | \`overlay\` | Confirmations, alerts | One at a time |
830
+ ---
761
831
 
762
- ### Pattern Selection by Intent
763
- | Intent | Patterns | Key Props |
764
- |--------|----------|-----------|
765
- | List/browse data | \`entity-table\`, \`entity-cards\`, \`entity-list\` | columns, itemActions, searchable |
766
- | Show metrics/KPIs | \`stats\` | metrics: [{label, value, icon, trend}] |
767
- | Filter/search | \`filter-group\`, \`search-input\` | filters (from entity enum fields) |
768
- | Create/edit form | \`form-section\` | fields, submitEvent, cancelEvent |
769
- | View details | \`entity-detail\`, \`detail-panel\` | fields/fieldNames, actions |
770
- | Organize content | \`tabs\` | tabs: [{label, content}] |
771
- | Dashboard layout | \`dashboard-grid\` | columns (number) |
772
- | Charts | \`chart\` | chartType, data, xAxis, yAxis |
773
- | Progress | \`progress-bar\`, \`meter\` | value, max, label |
774
- | Timeline | \`timeline\` | items: [{date, title, description}] |
775
- | Page heading | \`page-header\` | title, subtitle, actions |
776
- | Confirmation | \`confirmation\` | title, message, onConfirm, onCancel |
777
- | Master/detail | \`master-detail\` | Split list + detail |
778
- | Cards grid | \`entity-cards\` | columns, itemActions, layout |
832
+ ### Rule 1: Single Render-UI Per Transition
779
833
 
780
- ### Composition Recipes
834
+ Each transition executes exactly ONE render-ui effect with composed children:
781
835
 
782
- **CRUD Browsing INIT** (most common \u2014 compose ALL of these in main slot):
783
836
  \`\`\`json
784
- ["render-ui", "main", { "type": "page-header", "title": "Tasks", "subtitle": "Manage your tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
785
- ["render-ui", "main", { "type": "stats", "entity": "Task", "metrics": [{ "label": "Total", "value": "@count", "icon": "clipboard" }, { "label": "Active", "value": "@count:status=active", "icon": "clock" }, { "label": "Done", "value": "@count:status=done", "icon": "check-circle" }] }],
786
- ["render-ui", "main", { "type": "entity-table", "entity": "Task", "columns": ["title", "status", "createdAt"], "searchable": true, "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }]
787
- \`\`\`
837
+ // \u2705 CORRECT: Single render-ui with composed children
838
+ {
839
+ "from": "Browsing",
840
+ "to": "Browsing",
841
+ "event": "INIT",
842
+ "effects": [
843
+ ["render-ui", "main", {
844
+ "type": "stack",
845
+ "direction": "vertical",
846
+ "gap": "lg",
847
+ "children": [
848
+ { "type": "page-header", "title": "...", "actions": [...] },
849
+ { "type": "entity-table", "entity": "...", ... }
850
+ ]
851
+ }]
852
+ ]
853
+ }
788
854
 
789
- **Dashboard INIT**:
855
+ // \u274C WRONG: Multiple flat render-ui calls
856
+ {
857
+ "effects": [
858
+ ["render-ui", "main", { "type": "page-header", ... }],
859
+ ["render-ui", "main", { "type": "entity-table", ... }]
860
+ ]
861
+ }
790
862
  \`\`\`
791
- main: page-header \u2192 title + date range actions
792
- main: dashboard-grid \u2192 columns: 3
793
- main: stats \u2192 computed KPIs from entity counts
794
- main: chart \u2192 primary data visualization
795
- main: entity-cards \u2192 recent items (limit: 6)
863
+
864
+ ---
865
+
866
+ ### Rule 2: Three Atomic Levels Required
867
+
868
+ Every composition MUST contain ALL three levels:
869
+
870
+ #### Level 1: Atoms (Minimum 2 distinct types)
871
+
872
+ | Type | Purpose | Example Usage |
873
+ |------|---------|---------------|
874
+ | \`typography\` | All text content | Headlines, labels, body text |
875
+ | \`badge\` | Status indicators | Active, Pending, Completed |
876
+ | \`button\` | User actions | Create, Edit, Delete |
877
+ | \`avatar\` | User/entity images | Profile pictures |
878
+ | \`icon\` | Decorative icons | Plus, Edit, Trash |
879
+ | \`progress-bar\` | Progress indicators | Upload progress |
880
+ | \`divider\` | Visual separation | Section dividers |
881
+
882
+ #### Level 2: Molecules (Minimum 1)
883
+
884
+ | Type | Purpose | Example Usage |
885
+ |------|---------|---------------|
886
+ | \`box\` | Visual containers | Stat cards, panels |
887
+ | \`card\` | Content grouping | Feature cards |
888
+ | \`modal\` | Dialog overlays | Create/edit forms |
889
+ | \`drawer\` | Side panels | Detail views |
890
+ | \`tabs\` | Content organization | Filter tabs |
891
+ | \`alert\` | Notifications | Success/error messages |
892
+ | \`accordion\` | Collapsible sections | FAQ, settings |
893
+
894
+ #### Level 3: Organisms (Minimum 1 for data views)
895
+
896
+ | Type | Purpose | Example Usage |
897
+ |------|---------|---------------|
898
+ | \`entity-table\` | Data tables | List views |
899
+ | \`form-section\` | Forms | Create/edit |
900
+ | \`detail-panel\` | Detail views | View record |
901
+ | \`page-header\` | Page headers | Title + actions |
902
+ | \`chart\` | Data visualization | Analytics |
903
+ | \`timeline\` | Chronological events | Activity history |
904
+ | \`stats\` | KPI metrics | Dashboard stats |
905
+
906
+ ---
907
+
908
+ ### Rule 3: Layout-First Structure
909
+
910
+ Root element MUST be a layout primitive:
911
+
912
+ \`\`\`json
913
+ // \u2705 CORRECT: Layout wrappers
914
+ { "type": "stack", "direction": "vertical", "gap": "lg", "children": [...] }
915
+ { "type": "stack", "direction": "horizontal", "gap": "md", "children": [...] }
916
+ { "type": "box", "padding": "lg", "bg": "var(--color-card)", "children": [...] }
917
+ { "type": "container", "size": "xl", "padding": "lg", "children": [...] }
918
+ { "type": "grid", "cols": 3, "gap": "md", "children": [...] }
919
+
920
+ // \u274C WRONG: No layout wrapper
921
+ { "type": "page-header", "title": "..." }
922
+ { "type": "entity-table", "entity": "..." }
796
923
  \`\`\`
797
924
 
798
- **Detail View (drawer)**:
925
+ #### Layout Props Reference
926
+
927
+ **Stack (VStack/HStack)**
928
+ \`\`\`json
929
+ {
930
+ "type": "stack",
931
+ "direction": "vertical" | "horizontal",
932
+ "gap": "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl",
933
+ "align": "start" | "center" | "end" | "stretch",
934
+ "justify": "start" | "center" | "end" | "between" | "around",
935
+ "wrap": true | false
936
+ }
799
937
  \`\`\`
800
- drawer: entity-detail \u2192 all fields + [Edit, Delete] actions
801
- drawer: tabs \u2192 related collections (if entity has relation fields)
938
+
939
+ **Box**
940
+ \`\`\`json
941
+ {
942
+ "type": "box",
943
+ "padding": "none" | "xs" | "sm" | "md" | "lg" | "xl",
944
+ "bg": "var(--color-card)" | "var(--color-muted)" | "var(--color-primary)",
945
+ "border": true | false,
946
+ "borderColor": "var(--color-border)",
947
+ "rounded": "var(--radius-none)" | "var(--radius-sm)" | "var(--radius-md)" | "var(--radius-lg)" | "var(--radius-xl)",
948
+ "shadow": "var(--shadow-none)" | "var(--shadow-sm)" | "var(--shadow-md)" | "var(--shadow-lg)"
949
+ }
802
950
  \`\`\`
803
951
 
804
- **Wizard Flow**:
952
+ **Container**
953
+ \`\`\`json
954
+ {
955
+ "type": "container",
956
+ "size": "sm" | "md" | "lg" | "xl" | "full",
957
+ "padding": "none" | "xs" | "sm" | "md" | "lg" | "xl"
958
+ }
805
959
  \`\`\`
806
- main: wizard-progress \u2192 steps array + currentStep
807
- main: wizard-container \u2192 current step content
808
- main: wizard-navigation \u2192 Back/Next/Submit buttons
960
+
961
+ **Grid**
962
+ \`\`\`json
963
+ {
964
+ "type": "grid",
965
+ "cols": 1 | 2 | 3 | 4 | 6 | 12 | { "sm": 1, "md": 2, "lg": 3 },
966
+ "gap": "none" | "xs" | "sm" | "md" | "lg" | "xl"
967
+ }
809
968
  \`\`\`
810
969
 
811
- ### Layout Composition (stack, box, grid)
970
+ ---
971
+
972
+ ### Rule 4: Theme Variable Enforcement
812
973
 
813
- Layout patterns wrap other patterns via \`children\` arrays for rich, structured views.
974
+ ALL visual properties MUST use CSS theme variables:
814
975
 
815
- **VStack** (vertical stack): \`{ "type": "stack", "direction": "vertical", ... }\`
816
- **HStack** (horizontal stack): \`{ "type": "stack", "direction": "horizontal", ... }\`
817
- **Box** (styled container): \`{ "type": "box", ... }\`
976
+ | Property | \u2705 CORRECT | \u274C WRONG |
977
+ |----------|-----------|----------|
978
+ | Colors | "var(--color-primary)" | "#3b82f6", "blue", "white" |
979
+ | Backgrounds | "var(--color-card)" | "#ffffff", "white" |
980
+ | Text colors | "var(--color-foreground)" | "#000000", "black" |
981
+ | Spacing | "var(--spacing-lg)" | "16px", "1rem" |
982
+ | Radius | "var(--radius-md)" | "8px", "0.5rem" |
983
+ | Shadows | "var(--shadow-sm)" | "0 2px 4px rgba(0,0,0,0.1)" |
818
984
 
819
- #### Stack Props
820
- | Prop | Values | Default |
821
- |------|--------|---------|
822
- | \`direction\` | \`"vertical"\`, \`"horizontal"\` | \`"vertical"\` |
823
- | \`gap\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` | \`"md"\` |
824
- | \`align\` | \`"start"\`, \`"center"\`, \`"end"\`, \`"stretch"\` | \`"stretch"\` |
825
- | \`justify\` | \`"start"\`, \`"center"\`, \`"end"\`, \`"between"\`, \`"around"\` | \`"start"\` |
826
- | \`wrap\` | \`true\`, \`false\` | \`false\` |
985
+ ---
986
+
987
+ ### Rule 5: Template-Quality Composition
988
+
989
+ Match the sophistication of reference templates in \`packages/almadar-ui/components/templates/\`.
990
+
991
+ #### CrudTemplate Structure
992
+ \`\`\`
993
+ Container (size: xl, padding: lg)
994
+ \u2514\u2500\u2500 VStack (gap: lg)
995
+ \u251C\u2500\u2500 PageHeader (title + actions)
996
+ \u251C\u2500\u2500 Alert (error state)
997
+ \u251C\u2500\u2500 EntityTable (searchable, sortable, actions)
998
+ \u2514\u2500\u2500 Modal (form-section for create/edit)
999
+ \`\`\`
1000
+
1001
+ #### ListTemplate Structure
1002
+ \`\`\`
1003
+ Container (size: md, padding: lg)
1004
+ \u2514\u2500\u2500 VStack (gap: lg)
1005
+ \u251C\u2500\u2500 Typography (h2 title)
1006
+ \u251C\u2500\u2500 Input (search)
1007
+ \u251C\u2500\u2500 HStack (filter buttons)
1008
+ \u2514\u2500\u2500 VStack (list items)
1009
+ \`\`\`
1010
+
1011
+ #### Dashboard Structure
1012
+ \`\`\`
1013
+ Container (size: full, padding: lg)
1014
+ \u2514\u2500\u2500 Grid (cols: { sm: 1, md: 2, lg: 4 })
1015
+ \u251C\u2500\u2500 Box (stat card 1)
1016
+ \u251C\u2500\u2500 Box (stat card 2)
1017
+ \u251C\u2500\u2500 Box (stat card 3)
1018
+ \u2514\u2500\u2500 Box (stat card 4)
1019
+ \`\`\`
827
1020
 
828
- #### Box Props
829
- | Prop | Values |
830
- |------|--------|
831
- | \`padding\` / \`paddingX\` / \`paddingY\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` |
832
- | \`bg\` | \`"default"\`, \`"muted"\`, \`"card"\`, \`"primary"\`, \`"secondary"\`, \`"accent"\` |
833
- | \`border\` | \`true\`, \`false\` |
834
- | \`rounded\` | \`"none"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"full"\` |
835
- | \`shadow\` | \`"none"\`, \`"sm"\`, \`"md"\`, \`"lg"\` |
1021
+ #### Stats Cards - Static Text Only
836
1022
 
837
- #### Grid Props
838
- | Prop | Values |
839
- |------|--------|
840
- | \`cols\` | \`1\`\u2013\`12\` or \`{ sm: 1, md: 2, lg: 3 }\` |
841
- | \`gap\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` |
1023
+ For stats/overview sections, use **static text labels**, NOT computed bindings:
842
1024
 
843
- #### Nesting Example \u2014 Page Header + Stats Row + Table
844
1025
  \`\`\`json
845
- ["render-ui", "main", {
846
- "type": "stack", "direction": "vertical", "gap": "lg",
1026
+ // \u2705 CORRECT: Static text for labels
1027
+ {
1028
+ "type": "box",
1029
+ "padding": "md",
1030
+ "bg": "var(--color-card)",
847
1031
  "children": [
848
- { "type": "stack", "direction": "horizontal", "justify": "between", "align": "center",
849
- "children": [
850
- { "type": "typography", "variant": "h1", "text": "Orders" },
851
- { "type": "button", "label": "New Order", "event": "CREATE", "variant": "primary" }
852
- ]
853
- },
854
- { "type": "stack", "direction": "horizontal", "gap": "md", "wrap": true,
855
- "children": [
856
- { "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
857
- "children": [{ "type": "stats", "metrics": [{ "label": "Total", "value": "@count" }] }]
858
- },
859
- { "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
860
- "children": [{ "type": "stats", "metrics": [{ "label": "Pending", "value": "@count:status=pending" }] }]
861
- }
1032
+ { "type": "typography", "variant": "caption", "text": "Total Tasks" },
1033
+ { "type": "typography", "variant": "h2", "text": "--" }
1034
+ ]
1035
+ }
1036
+
1037
+ // \u2705 CORRECT: Using stats pattern with entity
1038
+ {
1039
+ "type": "stats",
1040
+ "entity": "Task",
1041
+ "label": "Total Tasks"
1042
+ }
1043
+
1044
+ // \u274C WRONG: Invented computed bindings
1045
+ { "text": "@count" }
1046
+ { "text": "@count:status=pending" }
1047
+ \`\`\`
1048
+
1049
+ ---
1050
+
1051
+ ### Validated Example: Task Management
1052
+
1053
+ This example has been validated with \`npx @almadar/cli validate\`:
1054
+
1055
+ \`\`\`json
1056
+ {
1057
+ "name": "Taskly",
1058
+ "version": "1.0.0",
1059
+ "orbitals": [{
1060
+ "name": "Task Management",
1061
+ "entity": {
1062
+ "name": "Task",
1063
+ "collection": "tasks",
1064
+ "fields": [
1065
+ { "name": "title", "type": "string", "required": true },
1066
+ { "name": "status", "type": "enum", "values": ["pending", "active", "done"] },
1067
+ { "name": "priority", "type": "enum", "values": ["low", "medium", "high"] }
862
1068
  ]
863
1069
  },
864
- { "type": "entity-table", "entity": "Order", "columns": ["customer", "total", "status"], "searchable": true }
865
- ]
866
- }]
1070
+ "traits": [{
1071
+ "name": "TaskInteraction",
1072
+ "category": "interaction",
1073
+ "linkedEntity": "Task",
1074
+ "emits": [{ "event": "INIT", "scope": "internal" }],
1075
+ "stateMachine": {
1076
+ "states": [
1077
+ { "name": "Browsing", "isInitial": true },
1078
+ { "name": "Creating" }
1079
+ ],
1080
+ "events": [
1081
+ { "key": "INIT", "name": "Initialize" },
1082
+ { "key": "CREATE", "name": "Create" },
1083
+ { "key": "SAVE", "name": "Save", "payload": [{ "name": "data", "type": "object" }] },
1084
+ { "key": "CANCEL", "name": "Cancel" }
1085
+ ],
1086
+ "transitions": [
1087
+ {
1088
+ "from": "Browsing",
1089
+ "to": "Browsing",
1090
+ "event": "INIT",
1091
+ "effects": [
1092
+ ["render-ui", "main", {
1093
+ "type": "stack",
1094
+ "direction": "vertical",
1095
+ "gap": "lg",
1096
+ "children": [
1097
+ {
1098
+ "type": "page-header",
1099
+ "title": "Task Management",
1100
+ "actions": [{ "label": "Create Task", "event": "CREATE", "variant": "primary" }]
1101
+ },
1102
+ {
1103
+ "type": "entity-table",
1104
+ "entity": "Task",
1105
+ "columns": ["title", "status", "priority"],
1106
+ "searchable": true,
1107
+ "itemActions": [
1108
+ { "label": "Edit", "event": "EDIT" },
1109
+ { "label": "Delete", "event": "DELETE" }
1110
+ ]
1111
+ }
1112
+ ]
1113
+ }]
1114
+ ]
1115
+ },
1116
+ {
1117
+ "from": "Browsing",
1118
+ "to": "Creating",
1119
+ "event": "CREATE",
1120
+ "effects": [
1121
+ ["render-ui", "modal", {
1122
+ "type": "form-section",
1123
+ "entity": "Task",
1124
+ "fields": ["title", "status", "priority"],
1125
+ "submitEvent": "SAVE",
1126
+ "cancelEvent": "CANCEL"
1127
+ }]
1128
+ ]
1129
+ },
1130
+ {
1131
+ "from": "Creating",
1132
+ "to": "Browsing",
1133
+ "event": "SAVE",
1134
+ "effects": [
1135
+ ["persist", "create", "Task", "@payload.data"],
1136
+ ["render-ui", "modal", null],
1137
+ ["emit", "INIT"]
1138
+ ]
1139
+ },
1140
+ {
1141
+ "from": "Creating",
1142
+ "to": "Browsing",
1143
+ "event": "CANCEL",
1144
+ "effects": [
1145
+ ["render-ui", "modal", null]
1146
+ ]
1147
+ }
1148
+ ]
1149
+ }
1150
+ }],
1151
+ "pages": [{
1152
+ "name": "TasksPage",
1153
+ "path": "/tasks",
1154
+ "viewType": "list",
1155
+ "isInitial": true,
1156
+ "entity": "Task",
1157
+ "traits": [{ "ref": "TaskInteraction" }]
1158
+ }],
1159
+ "emits": [],
1160
+ "listens": []
1161
+ }]
1162
+ }
1163
+ \`\`\`
1164
+
1165
+ ---
1166
+
1167
+ ${getBindingsGuide()}
1168
+
1169
+ ---
1170
+
1171
+ ### Critical Validation Rules
1172
+
1173
+ | Element | Correct Format | Wrong Format | Error |
1174
+ |---------|----------------|--------------|-------|
1175
+ | **Events** | \`{ "key": "INIT", "name": "Init" }\` | \`"INIT"\` | ORB_T_EVT_INVALID_FORMAT |
1176
+ | **Emits** | \`[{ "event": "INIT", "scope": "internal" }}]\` | \`["INIT"]\` | ORB_T_UNDEFINED_TRAIT |
1177
+ | **Payload events** | \`{ "key": "SAVE", "payload": [...] }\` | No payload | ORB_BINDING_PAYLOAD_FIELD_UNDECLARED |
1178
+ | **Page traits** | \`{ "ref": "TraitName" }\` | With linkedEntity | ORB_P_INVALID_TRAIT_REF |
1179
+ | **Category** | \`"category": "interaction"\` | Missing | ORB_T_MISSING_CATEGORY |
1180
+
1181
+ ---
1182
+
1183
+ ### Composition Quality Checklist
1184
+
1185
+ Before calling \`finish_task\`, verify:
1186
+
1187
+ \`\`\`
1188
+ \u25A1 Single render-ui per transition
1189
+ \u25A1 Root element is layout (stack/box/container/grid)
1190
+ \u25A1 Contains 2+ atoms (typography, badge, button, etc.)
1191
+ \u25A1 Contains 1+ molecules (box, card, tabs, alert)
1192
+ \u25A1 Contains 1+ organisms (entity-table, form-section, page-header)
1193
+ \u25A1 Uses theme variables for ALL visual properties
1194
+ \u25A1 Has 3+ distinct sections (header, content, actions)
1195
+ \u25A1 Matches template quality from almadar-ui/components/templates/
1196
+ \u25A1 Passes npx @almadar/cli validate with zero errors
867
1197
  \`\`\`
868
1198
 
869
- #### When to Use Layout Patterns
870
- - **VStack**: Default page layout \u2014 stack header, content sections, tables vertically
871
- - **HStack**: Side-by-side elements \u2014 stat cards, action buttons, header with controls
872
- - **Box**: Visual grouping \u2014 cards, panels, highlighted sections with borders/backgrounds
873
- - **Grid**: Equal-width columns \u2014 dashboard cards, stat grids, gallery layouts
1199
+ ---
1200
+
1201
+ ### BANNED Patterns
874
1202
 
875
- > **Tip**: A single \`render-ui\` call with a top-level \`stack\` containing nested children produces a more cohesive layout than multiple flat \`render-ui\` calls to the same slot.
1203
+ | Wrong | Correct |
1204
+ |-------|---------|
1205
+ | Multiple flat render-ui calls | Single composed render-ui |
1206
+ | Root organism without layout | Layout wrapper required |
1207
+ | Hex colors | Theme CSS variables |
1208
+ | Pixel values | Theme spacing variables |
1209
+ | Events as strings \`"INIT"\` | Event objects \`{ "key": "INIT" }\` |
1210
+ | Emits as strings \`["INIT"]\` | Emit objects \`[{ "event": "INIT" }]\` |
1211
+ | \`onSubmit\` / \`onCancel\` | \`submitEvent\` / \`cancelEvent\` |
1212
+ | \`headerActions\` | \`actions\` |
876
1213
 
877
- ### Domain-Aware Pattern Selection
878
- | Domain | List Pattern | Extras |
879
- |--------|-------------|--------|
880
- | business/admin | \`entity-table\` (searchable) | \`stats\`, \`filter-group\` |
881
- | ecommerce | \`entity-cards\` | \`stats\` (revenue), \`chart\` |
882
- | content/CMS | \`entity-cards\` | \`tabs\`, \`media-gallery\` |
883
- | dashboard | \`dashboard-grid\` | \`stats\`, \`chart\`, \`meter\`, \`timeline\` |
884
- | workflow | \`entity-table\` | \`progress-bar\`, \`timeline\` |
1214
+ ---
885
1215
 
886
1216
  ${getPatternPropsCompact()}
887
1217
 
@@ -889,6 +1219,244 @@ ${getPatternActionsRef()}
889
1219
  `;
890
1220
  }
891
1221
 
1222
+ // src/prompts/skill-sections/theme-guide.ts
1223
+ function getThemeGuide() {
1224
+ return `## Theme Variable System (MANDATORY)
1225
+
1226
+ All visual properties MUST use CSS theme variables. Never use hardcoded values.
1227
+
1228
+ ### \u274C BANNED: Hardcoded Values
1229
+
1230
+ | Type | Wrong | Why |
1231
+ |------|-------|-----|
1232
+ | Hex colors | "#3b82f6", "#ffffff", "#000000" | Not themeable |
1233
+ | Named colors | "white", "black", "red", "blue" | Not themeable |
1234
+ | Pixel values | "16px", "8px", "24px" | Not scalable |
1235
+ | Rem values | "1rem", "0.5rem" | Inconsistent |
1236
+ | Arbitrary values | "0 2px 4px rgba(0,0,0,0.1)" | Not themeable |
1237
+
1238
+ ### \u2705 REQUIRED: Theme Variables
1239
+
1240
+ ### Color Variables
1241
+
1242
+ | Variable | Usage | Example Context |
1243
+ |----------|-------|-----------------|
1244
+ | \`var(--color-foreground)\` | Primary text | Headlines, body text |
1245
+ | \`var(--color-muted-foreground)\` | Secondary text | Captions, labels, hints |
1246
+ | \`var(--color-background)\` | Page background | Main container bg |
1247
+ | \`var(--color-card)\` | Card backgrounds | Box containers, panels |
1248
+ | \`var(--color-muted)\` | Subtle sections | Alternating rows, disabled states |
1249
+ | \`var(--color-primary)\` | Primary actions | Main buttons, active states |
1250
+ | \`var(--color-primary-foreground)\` | Text on primary | Button labels |
1251
+ | \`var(--color-secondary)\` | Secondary actions | Secondary buttons |
1252
+ | \`var(--color-secondary-foreground)\` | Text on secondary | Secondary button labels |
1253
+ | \`var(--color-success)\` | Success states | Completed badges, success alerts |
1254
+ | \`var(--color-warning)\` | Warnings | Warning badges, alerts |
1255
+ | \`var(--color-destructive)\` | Errors, delete | Danger buttons, error states |
1256
+ | \`var(--color-border)\` | Borders, dividers | Card outlines, separators |
1257
+ | \`var(--color-input)\` | Input backgrounds | Form field backgrounds |
1258
+ | \`var(--color-ring)\` | Focus rings | Input focus states |
1259
+
1260
+ ### Spacing Variables
1261
+
1262
+ | Variable | Value | Usage |
1263
+ |----------|-------|-------|
1264
+ | \`var(--spacing-xs)\` | 4px | Tight gaps, icon spacing |
1265
+ | \`var(--spacing-sm)\` | 8px | Small gaps, compact layouts |
1266
+ | \`var(--spacing-md)\` | 12px | Standard gaps |
1267
+ | \`var(--spacing-lg)\` | 16px | Large gaps, section padding |
1268
+ | \`var(--spacing-xl)\` | 24px | Extra large gaps |
1269
+ | \`var(--spacing-2xl)\` | 32px | Page-level spacing |
1270
+ | \`var(--spacing-3xl)\` | 48px | Major section spacing |
1271
+ | \`var(--spacing-4xl)\` | 64px | Hero section spacing |
1272
+
1273
+ ### Radius Variables
1274
+
1275
+ | Variable | Value | Usage |
1276
+ |----------|-------|-------|
1277
+ | \`var(--radius-none)\` | 0px | Sharp corners |
1278
+ | \`var(--radius-sm)\` | 2px | Small elements, tags |
1279
+ | \`var(--radius-md)\` | 6px | Buttons, inputs, small cards |
1280
+ | \`var(--radius-lg)\` | 8px | Cards, panels, modals |
1281
+ | \`var(--radius-xl)\` | 12px | Large containers |
1282
+ | \`var(--radius-2xl)\` | 16px | Extra large containers |
1283
+ | \`var(--radius-full)\` | 9999px | Pills, avatars, badges |
1284
+
1285
+ ### Shadow Variables
1286
+
1287
+ | Variable | Usage |
1288
+ |----------|-------|
1289
+ | \`var(--shadow-none)\` | Flat design, no elevation |
1290
+ | \`var(--shadow-sm)\` | Subtle elevation, cards |
1291
+ | \`var(--shadow-md)\` | Cards, dropdowns, popovers |
1292
+ | \`var(--shadow-lg)\` | Modals, dialogs |
1293
+ | \`var(--shadow-xl)\` | High elevation elements |
1294
+ | \`var(--shadow-2xl)\` | Maximum elevation |
1295
+
1296
+ ### Pattern-Specific Examples
1297
+
1298
+ #### Box / Card Container
1299
+ \`\`\`json
1300
+ {
1301
+ "type": "box",
1302
+ "padding": "lg",
1303
+ "bg": "var(--color-card)",
1304
+ "border": true,
1305
+ "borderColor": "var(--color-border)",
1306
+ "rounded": "var(--radius-lg)",
1307
+ "shadow": "var(--shadow-sm)"
1308
+ }
1309
+ \`\`\`
1310
+
1311
+ #### Typography
1312
+ \`\`\`json
1313
+ // Page title
1314
+ {
1315
+ "type": "typography",
1316
+ "variant": "h1",
1317
+ "text": "Page Title",
1318
+ "color": "var(--color-foreground)"
1319
+ }
1320
+
1321
+ // Secondary text
1322
+ {
1323
+ "type": "typography",
1324
+ "variant": "caption",
1325
+ "text": "Label text",
1326
+ "color": "var(--color-muted-foreground)"
1327
+ }
1328
+
1329
+ // Success text
1330
+ {
1331
+ "type": "typography",
1332
+ "variant": "body",
1333
+ "text": "Completed",
1334
+ "color": "var(--color-success)"
1335
+ }
1336
+ \`\`\`
1337
+
1338
+ #### Button (use variant, not manual colors)
1339
+ \`\`\`json
1340
+ // Primary action
1341
+ {
1342
+ "type": "button",
1343
+ "label": "Save",
1344
+ "event": "SAVE",
1345
+ "variant": "primary"
1346
+ }
1347
+
1348
+ // Secondary action
1349
+ {
1350
+ "type": "button",
1351
+ "label": "Cancel",
1352
+ "event": "CANCEL",
1353
+ "variant": "secondary"
1354
+ }
1355
+
1356
+ // Danger action
1357
+ {
1358
+ "type": "button",
1359
+ "label": "Delete",
1360
+ "event": "DELETE",
1361
+ "variant": "danger"
1362
+ }
1363
+ \`\`\`
1364
+
1365
+ #### Badge (variant maps to semantic colors)
1366
+ \`\`\`json
1367
+ {
1368
+ "type": "badge",
1369
+ "text": "Active",
1370
+ "variant": "primary"
1371
+ }
1372
+
1373
+ {
1374
+ "type": "badge",
1375
+ "text": "Completed",
1376
+ "variant": "success"
1377
+ }
1378
+
1379
+ {
1380
+ "type": "badge",
1381
+ "text": "Pending",
1382
+ "variant": "warning"
1383
+ }
1384
+
1385
+ {
1386
+ "type": "badge",
1387
+ "text": "Error",
1388
+ "variant": "danger"
1389
+ }
1390
+ \`\`\`
1391
+
1392
+ #### Stack Layout
1393
+ \`\`\`json
1394
+ {
1395
+ "type": "stack",
1396
+ "direction": "vertical",
1397
+ "gap": "lg",
1398
+ "align": "stretch",
1399
+ "justify": "start"
1400
+ }
1401
+ \`\`\`
1402
+
1403
+ ### Theme Validation Checklist
1404
+
1405
+ Before calling \`finish_task\`, verify:
1406
+
1407
+ - [ ] No hex colors (#fff, #000, #3b82f6, etc.)
1408
+ - [ ] No named colors (white, black, red, blue, etc.)
1409
+ - [ ] No pixel values (16px, 8px, 24px, etc.)
1410
+ - [ ] No rem values (1rem, 0.5rem, etc.)
1411
+ - [ ] All colors use var(--color-*)
1412
+ - [ ] All spacing uses var(--spacing-*)
1413
+ - [ ] All radius uses var(--radius-*)
1414
+ - [ ] All shadows use var(--shadow-*)
1415
+
1416
+ ### Auto-Correction Reference
1417
+
1418
+ The system will auto-correct these common mistakes:
1419
+
1420
+ | Wrong | Auto-Corrected To |
1421
+ |-------|-------------------|
1422
+ | "#fff" or "white" | "var(--color-background)" |
1423
+ | "#000" or "black" | "var(--color-foreground)" |
1424
+ | "#3b82f6" | "var(--color-primary)" |
1425
+ | "#10b981" | "var(--color-success)" |
1426
+ | "#f59e0b" | "var(--color-warning)" |
1427
+ | "#ef4444" | "var(--color-destructive)" |
1428
+ | "16px" | "var(--spacing-lg)" |
1429
+ | "8px" | "var(--spacing-sm)" |
1430
+ | "24px" | "var(--spacing-xl)" |
1431
+ | "8px" (radius) | "var(--radius-md)" |
1432
+ `;
1433
+ }
1434
+ function getBannedProps() {
1435
+ return `## BANNED PROPS (NEVER USE)
1436
+
1437
+ | Wrong Prop | Correct Prop | Pattern |
1438
+ |------------|--------------|---------|
1439
+ | \`onSubmit\` | \`submitEvent\` | form-section |
1440
+ | \`onCancel\` | \`cancelEvent\` | form-section |
1441
+ | \`headerActions\` | \`actions\` | detail-panel |
1442
+ | \`loading\` | \`isLoading\` | all patterns |
1443
+ | \`fieldNames\` | \`fields\` | detail-panel, form-section |
1444
+ | \`onConfirm\` | (use event transitions) | confirmation |
1445
+ | \`placement\` | (remove) | itemActions |
1446
+ | \`isDestructive\` | (use variant: "danger") | itemActions |
1447
+
1448
+ ### Banned Value Patterns
1449
+
1450
+ | Wrong | Correct |
1451
+ |-------|---------|
1452
+ | Hex colors: "#3b82f6" | Theme vars: "var(--color-primary)" |
1453
+ | Named colors: "white", "red" | Theme vars: "var(--color-background)" |
1454
+ | Pixel values: "16px" | Theme vars: "var(--spacing-lg)" |
1455
+ | Events as strings: "INIT" | Event objects: { "key": "INIT", "name": "Init" } |
1456
+ | Emits as strings: ["INIT"] | Emit objects: [{ "event": "INIT", "scope": "internal" }] |
1457
+ `;
1458
+ }
1459
+
892
1460
  // src/prompts/skill-sections/custom-traits.ts
893
1461
  function getCustomTraitSection() {
894
1462
  return `## Custom Trait Guide
@@ -968,7 +1536,7 @@ Every \`interaction\` trait MUST have:
968
1536
  "title": "In Review"
969
1537
  }],
970
1538
  ["render-ui", "main", {
971
- "type": "entity-detail",
1539
+ "type": "detail-panel",
972
1540
  "entity": "Document",
973
1541
  "fieldNames": ["title", "content"]
974
1542
  }],
@@ -1004,7 +1572,7 @@ Every \`interaction\` trait MUST have:
1004
1572
  "title": "Published!"
1005
1573
  }],
1006
1574
  ["render-ui", "main", {
1007
- "type": "entity-detail",
1575
+ "type": "detail-panel",
1008
1576
  "entity": "Document"
1009
1577
  }]
1010
1578
  ]
@@ -1148,7 +1716,7 @@ When traits need to communicate across orbitals, you MUST:
1148
1716
  | \`page-header\` | \`actions: [{label, event}]\` | Top-right buttons (New, Export) |
1149
1717
  | \`form-section\` | \`onSubmit\`, \`onCancel\` | Form submit/cancel buttons |
1150
1718
  | \`entity-table\` | \`itemActions: [{label, event}]\` | Row action buttons (Edit, Delete) |
1151
- | \`entity-detail\` | \`headerActions: [{label, event}]\` | Detail view header buttons |
1719
+ | \`detail-panel\` | \`actions: [{label, event}]\` | Detail view header buttons |
1152
1720
  | \`confirmation\` | \`onConfirm\`, \`onCancel\` | Confirmation dialog buttons |
1153
1721
  `;
1154
1722
  }
@@ -1557,7 +2125,7 @@ function getCommonFixPatternsSection() {
1557
2125
  | \`entity-table\` | itemActions | \`"itemActions": [{ "label": "Edit", "event": "EDIT" }]\` |
1558
2126
  | \`form-section\` | onSubmit | \`"onSubmit": "SAVE"\` |
1559
2127
  | \`form-section\` | fields | \`"fields": ["field1", "field2"]\` |
1560
- | \`entity-detail\` | fieldNames | \`"fieldNames": ["field1", "field2"]\` |
2128
+ | \`detail-panel\` | fields | \`"fields": ["field1", "field2"]\` |
1561
2129
  | \`page-header\` | actions | \`"actions": [{ "label": "New", "event": "CREATE" }]\` |`;
1562
2130
  }
1563
2131
  function getOverGenerationSection() {
@@ -2020,6 +2588,14 @@ ${getSExprQuickRef()}
2020
2588
 
2021
2589
  ${includeDesignGuide ? getRenderUIDesignGuide() : ""}
2022
2590
 
2591
+ ${includeDesignGuide ? `---
2592
+
2593
+ ${getThemeGuide()}
2594
+
2595
+ ---
2596
+
2597
+ ${getBannedProps()}` : ""}
2598
+
2023
2599
  ${stdSection}
2024
2600
  ---
2025
2601
 
@@ -2131,55 +2707,29 @@ finish_task({ appName: "App" })
2131
2707
  # Reads .orbitals/*.json \u2192 schema.json \u2192 orbital validate
2132
2708
  \`\`\`
2133
2709
 
2134
- ### Phase 4: DESIGN REFINEMENT (optional but recommended)
2135
-
2136
- After \`finish_task\` produces \`schema.json\`, enhance key transitions with \`design_transition\`.
2137
-
2138
- **When to use**: INIT transitions (they benefit most from rich composition \u2014 header + stats + content), and CREATE/VIEW transitions for polished forms and detail views.
2139
-
2140
- **Step-by-step:**
2141
-
2142
- 1. Call \`design_transition\` for the transition:
2143
- \`\`\`json
2144
- {
2145
- "from": "Browsing", "to": "Browsing", "event": "INIT",
2146
- "slot": "main", "entityName": "Task",
2147
- "entityFields": [{"name": "title", "type": "string"}, {"name": "status", "type": "enum", "values": ["pending", "active", "done"]}],
2148
- "domainCategory": "business"
2149
- }
2150
- \`\`\`
2151
- Returns: \`{ "success": true, "effects": [["render-ui", "main", {...}], ...] }\`
2152
-
2153
- 2. Extract the orbital chunk:
2154
- \`\`\`json
2155
- { "file": "schema.json", "type": "orbital", "name": "Task Management" }
2156
- \`\`\`
2157
-
2158
- 3. Edit the chunk file: replace render-ui effects in the target transition with the designed effects. **Keep all non-render-ui effects** (persist, emit, set) \u2014 only replace the render-ui tuples.
2710
+ ### Phase 4: VERIFY COMPOSITION QUALITY
2159
2711
 
2160
- 4. Apply the chunk back:
2161
- \`\`\`json
2162
- { "chunkId": "<id from extract_chunk>" }
2163
- \`\`\`
2712
+ Before calling \`finish_task\`, verify each INIT transition:
2164
2713
 
2165
- **Splicing rule**: For a transition with mixed effects like:
2166
- \`\`\`json
2167
- [["persist", "create", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
2168
- \`\`\`
2169
- Keep \`persist\` and \`emit\`, replace \`render-ui\` with the designed effects.
2170
- For INIT transitions (render-ui only), replace all effects.
2714
+ 1. **Uses a single \`render-ui\` call** with top-level \`stack\` and \`children\` \u2014 NOT flat sequential calls
2715
+ 2. **Has 3+ composed sections**: header (HStack: title + action), metrics (HStack/Grid of Box cards), data (entity-table/entity-cards)
2716
+ 3. **Uses domain-appropriate atoms**: \`badge\` for status, \`typography\` for labels/values, \`button\` for actions
2717
+ 4. **Props are correct**: \`submitEvent\` not \`onSubmit\`, \`actions\` not \`headerActions\`, \`fields\` not \`fieldNames\`
2171
2718
 
2172
- **Skip design_transition for**: SAVE, CANCEL, CONFIRM_DELETE transitions (they have persist/emit effects with simple slot-clearing \u2014 no UI to design).
2719
+ If any INIT transition is flat (just \`page-header\` + \`entity-table\`), redesign it as a composed VStack hierarchy before finishing.
2173
2720
  `;
2174
2721
  }
2175
2722
  function getMinimalExample() {
2176
2723
  return `---
2177
2724
 
2178
- ## Example: Task Manager
2725
+ ## Example: Task Manager (Atomic Composition - VALIDATED)
2726
+
2727
+ This example passes \`npx @almadar/cli validate\` with zero errors:
2179
2728
 
2180
2729
  \`\`\`json
2181
2730
  {
2182
2731
  "name": "Taskly",
2732
+ "version": "1.0.0",
2183
2733
  "orbitals": [{
2184
2734
  "name": "Task Management",
2185
2735
  "entity": {
@@ -2194,40 +2744,51 @@ function getMinimalExample() {
2194
2744
  "name": "TaskInteraction",
2195
2745
  "category": "interaction",
2196
2746
  "linkedEntity": "Task",
2747
+ "emits": [{ "event": "INIT", "scope": "internal" }],
2197
2748
  "stateMachine": {
2198
2749
  "states": [
2199
2750
  { "name": "Browsing", "isInitial": true },
2200
- { "name": "Creating" },
2201
- { "name": "Viewing" },
2202
- { "name": "Editing" },
2203
- { "name": "Deleting" }
2751
+ { "name": "Creating" }
2752
+ ],
2753
+ "events": [
2754
+ { "key": "INIT", "name": "Initialize" },
2755
+ { "key": "CREATE", "name": "Create" },
2756
+ { "key": "SAVE", "name": "Save", "payload": [{ "name": "data", "type": "object" }] },
2757
+ { "key": "CANCEL", "name": "Cancel" }
2204
2758
  ],
2205
- "events": ["INIT", "CREATE", "VIEW", "EDIT", "DELETE", "SAVE", "CANCEL", "CONFIRM_DELETE"],
2206
2759
  "transitions": [
2207
2760
  {
2208
2761
  "from": "Browsing", "to": "Browsing", "event": "INIT",
2209
2762
  "effects": [
2210
- ["render-ui", "main", { "type": "page-header", "title": "Tasks", "subtitle": "Manage your tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
2211
- ["render-ui", "main", { "type": "stats", "entity": "Task", "metrics": [{ "label": "Total", "value": "@count", "icon": "clipboard" }, { "label": "Active", "value": "@count:status=active", "icon": "clock" }, { "label": "Done", "value": "@count:status=done", "icon": "check-circle" }] }],
2212
- ["render-ui", "main", { "type": "entity-table", "entity": "Task", "columns": ["title", "status"], "searchable": true, "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }]
2763
+ ["render-ui", "main", {
2764
+ "type": "stack", "direction": "vertical", "gap": "lg",
2765
+ "children": [
2766
+ { "type": "stack", "direction": "horizontal", "justify": "between", "align": "center",
2767
+ "children": [
2768
+ { "type": "typography", "variant": "h1", "text": "Tasks" },
2769
+ { "type": "button", "label": "New Task", "event": "CREATE", "variant": "primary" }
2770
+ ]
2771
+ },
2772
+ { "type": "stack", "direction": "horizontal", "gap": "md", "wrap": true,
2773
+ "children": [
2774
+ { "type": "box", "padding": "md", "bg": "var(--color-card)", "border": true, "rounded": "var(--radius-md)",
2775
+ "children": [{ "type": "typography", "variant": "caption", "text": "Total" }, { "type": "typography", "variant": "h2", "text": "@count" }] },
2776
+ { "type": "box", "padding": "md", "bg": "var(--color-card)", "border": true, "rounded": "var(--radius-md)",
2777
+ "children": [{ "type": "typography", "variant": "caption", "text": "Active" }, { "type": "badge", "variant": "primary", "text": "@count:status=active" }] },
2778
+ { "type": "box", "padding": "md", "bg": "var(--color-card)", "border": true, "rounded": "var(--radius-md)",
2779
+ "children": [{ "type": "typography", "variant": "caption", "text": "Done" }, { "type": "badge", "variant": "success", "text": "@count:status=done" }] }
2780
+ ]
2781
+ },
2782
+ { "type": "entity-table", "entity": "Task", "columns": ["title", "status"], "searchable": true,
2783
+ "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }
2784
+ ]
2785
+ }]
2213
2786
  ]
2214
2787
  },
2215
2788
  {
2216
2789
  "from": "Browsing", "to": "Creating", "event": "CREATE",
2217
2790
  "effects": [["render-ui", "modal", { "type": "form-section", "entity": "Task", "fields": ["title", "status"], "submitEvent": "SAVE", "cancelEvent": "CANCEL" }]]
2218
2791
  },
2219
- {
2220
- "from": "Browsing", "to": "Viewing", "event": "VIEW",
2221
- "effects": [["render-ui", "drawer", { "type": "entity-detail", "entity": "Task", "actions": [{ "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE", "variant": "danger" }] }]]
2222
- },
2223
- {
2224
- "from": "Browsing", "to": "Editing", "event": "EDIT",
2225
- "effects": [["render-ui", "modal", { "type": "form-section", "entity": "Task", "fields": ["title", "status"], "submitEvent": "SAVE", "cancelEvent": "CANCEL" }]]
2226
- },
2227
- {
2228
- "from": "Browsing", "to": "Deleting", "event": "DELETE",
2229
- "effects": [["render-ui", "overlay", { "type": "confirmation", "title": "Delete Task?", "message": "This action cannot be undone." }]]
2230
- },
2231
2792
  {
2232
2793
  "from": "Creating", "to": "Browsing", "event": "SAVE",
2233
2794
  "effects": [["persist", "create", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
@@ -2235,15 +2796,7 @@ function getMinimalExample() {
2235
2796
  {
2236
2797
  "from": "Creating", "to": "Browsing", "event": "CANCEL",
2237
2798
  "effects": [["render-ui", "modal", null]]
2238
- },
2239
- {
2240
- "from": "Viewing", "to": "Browsing", "event": "CANCEL",
2241
- "effects": [["render-ui", "drawer", null]]
2242
- },
2243
- {
2244
- "from": "Editing", "to": "Browsing", "event": "SAVE",
2245
- "effects": [["persist", "update", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
2246
- },
2799
+ }
2247
2800
  {
2248
2801
  "from": "Editing", "to": "Browsing", "event": "CANCEL",
2249
2802
  "effects": [["render-ui", "modal", null]]
@@ -2259,24 +2812,35 @@ function getMinimalExample() {
2259
2812
  ]
2260
2813
  }
2261
2814
  }],
2262
- "pages": [{ "name": "TasksPage", "path": "/tasks", "traits": [{ "ref": "TaskInteraction" }] }]
2815
+ "pages": [{
2816
+ "name": "TasksPage",
2817
+ "path": "/tasks",
2818
+ "viewType": "list",
2819
+ "isInitial": true,
2820
+ "entity": "Task",
2821
+ "traits": [{ "ref": "TaskInteraction" }]
2822
+ }],
2823
+ "emits": [],
2824
+ "listens": []
2263
2825
  }]
2264
2826
  }
2265
2827
  \`\`\`
2266
2828
 
2267
- **Key points**:
2268
- - ONE page (TasksPage) not four (list/create/edit/view)
2269
- - INIT transition composes **multiple patterns**: page-header + stats + entity-table
2270
- - States are OBJECTS with \`isInitial\` flag
2271
- - **Actions are INSIDE patterns (use unified props)**:
2272
- - \`page-header\` has \`actions: [{label, event, variant}]\`
2273
- - \`entity-table\` has \`itemActions: [{label, event}]\` and \`searchable: true\`
2274
- - \`form-section\` has \`submitEvent\` and \`cancelEvent\` (NOT onSubmit/onCancel!)
2275
- - \`entity-detail\` has \`actions\` (NOT headerActions!)
2276
- - \`confirmation\` emits action events
2277
- - \`stats\` has \`metrics: [{label, value, icon}]\`
2278
- - **NEVER use**: \`onSubmit\`, \`onCancel\`, \`headerActions\`, \`loading\` (use \`isLoading\`)
2279
- - NO separate "form-actions" pattern - it doesn't exist!
2829
+ **Key points \u2014 Atomic Composition**:
2830
+ - **INIT uses a SINGLE \`render-ui\` call** with a top-level \`stack\` containing composed \`children\`
2831
+ - **3 sections composed**: header (HStack: title + button), metrics (HStack of Box stat cards), data (entity-table)
2832
+ - **Atoms used**: \`typography\` (h1, h2, caption), \`badge\` (status indicators), \`button\` (actions)
2833
+ - **Layout used**: \`stack\` (vertical page, horizontal rows), \`box\` (stat cards)
2834
+ - **Organism used**: \`entity-table\` with searchable + itemActions
2835
+ - **Theme variables**: All colors use \`var(--color-*)\`, spacing uses \`var(--spacing-*)\`, radius uses \`var(--radius-*)\`
2836
+
2837
+ **Validation Rules** (MANDATORY):
2838
+ - Events: \`{ "key": "INIT", "name": "Initialize" }\` \u2014 NOT \`"INIT"\`
2839
+ - Emits: \`[{ "event": "INIT", "scope": "internal" }]\` \u2014 NOT \`["INIT"]\`
2840
+ - Payload events MUST declare payload: \`{ "key": "SAVE", "payload": [{ "name": "data", "type": "object" }] }\`
2841
+ - Page traits: \`{ "ref": "TaskInteraction" }\` \u2014 NOT with linkedEntity
2842
+ - Props: \`submitEvent\` (not \`onSubmit\`), \`actions\` (not \`headerActions\`), \`fields\` (not \`fieldNames\`)
2843
+ - Theme: All visual properties use CSS variables
2280
2844
  `;
2281
2845
  }
2282
2846
 
@@ -2285,9 +2849,9 @@ function generateKflowOrbitalsSkill(compact = false) {
2285
2849
  const frontmatter = {
2286
2850
  name: "kflow-orbitals",
2287
2851
  description: "Generate KFlow schemas using the Orbitals composition model. Decomposes applications into atomic Orbital Units (Entity x Traits x Patterns) with structural caching for efficiency.",
2288
- allowedTools: ["Read", "Write", "Edit", "generate_orbital", "design_transition", "finish_task", "query_schema_structure", "extract_chunk", "apply_chunk"],
2289
- version: "4.1.0"
2290
- // v4.1: design refinement workflow with design_transition
2852
+ allowedTools: ["Read", "Write", "Edit", "generate_orbital", "finish_task", "query_schema_structure", "extract_chunk", "apply_chunk"],
2853
+ version: "5.0.0"
2854
+ // v5.0: atomic composition (removed design_transition, single-pass design)
2291
2855
  };
2292
2856
  const content = generateLeanOrbitalSkill({
2293
2857
  includeExample: true,
@@ -2608,7 +3172,7 @@ Output the complete updated domain language text.
2608
3172
  2. **Follow naming conventions** - PascalCase for entities/pages, camelCase for fields
2609
3173
  3. **Include all required fields** - Every entity needs at least one field
2610
3174
  4. **Define page paths** - Use RESTful URL patterns
2611
- 5. **Match patterns to view types** - list\u2192entity-list, detail\u2192entity-detail, create/edit\u2192form-section
3175
+ 5. **Match patterns to view types** - list\u2192entity-list/entity-table, detail\u2192detail-panel, create/edit\u2192form-section
2612
3176
  `.trim();
2613
3177
  return {
2614
3178
  name: "domain-language",
@@ -2616,353 +3180,6 @@ Output the complete updated domain language text.
2616
3180
  content
2617
3181
  };
2618
3182
  }
2619
- function getMinimalTypeReference() {
2620
- return `
2621
- ## Orbital Schema Structure
2622
-
2623
- \`\`\`typescript
2624
- interface OrbitalDefinition {
2625
- name: string; // Entity name (PascalCase)
2626
- entity: Entity; // Data model
2627
- traits: TraitRef[]; // State machines (names or definitions)
2628
- pages: Page[]; // Routes and views
2629
- emits?: string[]; // Events this orbital emits
2630
- listens?: EventListener[]; // Events this orbital listens to
2631
- }
2632
- \`\`\`
2633
-
2634
- ### Entity Fields
2635
-
2636
- \`\`\`typescript
2637
- { name: "title", type: "string", required: true }
2638
- { name: "count", type: "number", default: 0 }
2639
- { name: "status", type: "enum", values: ["pending", "active", "done"] }
2640
- { name: "dueDate", type: "date" }
2641
- \`\`\`
2642
-
2643
- ### Trait State Machine
2644
-
2645
- \`\`\`typescript
2646
- {
2647
- states: [{ name: "Idle", isInitial: true }, { name: "Active" }],
2648
- events: ["INIT", "ACTIVATE", "COMPLETE"],
2649
- transitions: [
2650
- { from: "Idle", to: "Active", event: "ACTIVATE",
2651
- guards: [["condition"]],
2652
- effects: [["action"]] }
2653
- ]
2654
- }
2655
- \`\`\`
2656
- `.trim();
2657
- }
2658
- function getPatternTypesCompact() {
2659
- const patterns = getAllPatternTypes();
2660
- return `
2661
- ## Available Pattern Types
2662
-
2663
- ${patterns.map((p) => `- \`${p}\``).join("\n")}
2664
-
2665
- ${getPatternPropsCompact()}
2666
- `.trim();
2667
- }
2668
- function getSExprQuickRef2() {
2669
- const operators = Object.keys(OPERATORS).slice(0, 15);
2670
- return `
2671
- ## S-Expression Quick Reference
2672
-
2673
- ### Guard Expressions (Conditions)
2674
-
2675
- \`\`\`typescript
2676
- ["=", "@entity.status", "active"] // Equality
2677
- [">", "@entity.count", 0] // Greater than
2678
- ["and", ["cond1"], ["cond2"]] // Logical AND
2679
- ["or", ["cond1"], ["cond2"]] // Logical OR
2680
- ["not", ["condition"]] // Logical NOT
2681
- \`\`\`
2682
-
2683
- ### Effect Expressions (Actions)
2684
-
2685
- \`\`\`typescript
2686
- ["set", "@entity.field", value] // Update field
2687
- ["emit", "EVENT_NAME", payload] // Emit event
2688
- ["navigate", "/path"] // Navigate to route
2689
- ["render-ui", "main", { type, props }] // Render pattern
2690
- ["persist", "create", "Entity", data] // Database operation
2691
- \`\`\`
2692
-
2693
- ### Available Operators
2694
-
2695
- ${operators.map((op) => `- \`${op}\``).join("\n")}
2696
- `.trim();
2697
- }
2698
- function getRenderUIQuickRef2() {
2699
- const slots = UI_SLOTS;
2700
- return `
2701
- ## Render-UI Effect Reference
2702
-
2703
- ### Syntax
2704
-
2705
- \`\`\`typescript
2706
- ["render-ui", slot, patternConfig | null]
2707
- \`\`\`
2708
-
2709
- ### UI Slots
2710
-
2711
- ${slots.map((slot) => `- \`${slot}\``).join("\n")}
2712
-
2713
- ### Example
2714
-
2715
- \`\`\`typescript
2716
- ["render-ui", "main", {
2717
- type: "entity-table",
2718
- entity: "Task",
2719
- columns: ["title", "status"],
2720
- itemActions: [{ label: "Edit", event: "EDIT" }]
2721
- }]
2722
- \`\`\`
2723
-
2724
- Clear slot: \`["render-ui", "modal", null]\`
2725
- `.trim();
2726
- }
2727
- function getFieldTypesCompact() {
2728
- return `
2729
- ## Field Types
2730
-
2731
- | Type | Example | Notes |
2732
- |------|---------|-------|
2733
- | \`string\` | \`{ name: "title", type: "string" }\` | Text |
2734
- | \`number\` | \`{ name: "count", type: "number" }\` | Integer or float |
2735
- | \`boolean\` | \`{ name: "active", type: "boolean" }\` | true/false |
2736
- | \`date\` | \`{ name: "birthday", type: "date" }\` | Date only |
2737
- | \`timestamp\` | \`{ name: "createdAt", type: "timestamp" }\` | Date + time |
2738
- | \`enum\` | \`{ name: "status", type: "enum", values: ["a", "b"] }\` | Fixed options |
2739
- | \`array\` | \`{ name: "tags", type: "array", items: "string" }\` | List |
2740
- | \`relation\` | \`{ name: "user", type: "relation", relation: { entity: "User", cardinality: "one" } }\` | Foreign key |
2741
-
2742
- ### Field Properties
2743
-
2744
- - \`required: true\` - Must have value
2745
- - \`default: value\` - Default value
2746
- - \`unique: true\` - Must be unique
2747
- `.trim();
2748
- }
2749
-
2750
- // src/generators/kflow-design.ts
2751
- function getTransitionContextGuide() {
2752
- return `## Transition Context
2753
-
2754
- You receive a single transition to design. Use these inputs to make UI decisions:
2755
-
2756
- ### Input Fields
2757
- | Field | What It Tells You |
2758
- |-------|-------------------|
2759
- | \`from\` | Current state (e.g., "Browsing", "Creating") |
2760
- | \`to\` | Target state (e.g., "Browsing", "Viewing") |
2761
- | \`event\` | What the user did (e.g., "INIT", "CREATE", "VIEW") |
2762
- | \`currentSlot\` | Which slot to render into (\`main\`, \`modal\`, \`drawer\`) |
2763
- | \`entity\` | Entity name + fields (drives column/field selection) |
2764
- | \`designHints\` | Style + UX hints from decomposition |
2765
- | \`domainContext\` | Category + vocabulary (drives pattern choice) |
2766
- | \`existingEffects\` | Current render-ui effects (if enhancing) |
2767
-
2768
- ### Decision Flow
2769
-
2770
- \`\`\`
2771
- 1. What EVENT is this?
2772
- \u251C\u2500 INIT \u2192 Compose full page layout (header + content + data)
2773
- \u251C\u2500 CREATE/EDIT \u2192 Form in modal or drawer
2774
- \u251C\u2500 VIEW \u2192 Detail in drawer or inline
2775
- \u251C\u2500 DELETE \u2192 Confirmation in overlay
2776
- \u2514\u2500 SAVE/CANCEL \u2192 Clear slot (return null)
2777
-
2778
- 2. What SLOT?
2779
- \u251C\u2500 main \u2192 Compose multiple patterns (stack them)
2780
- \u251C\u2500 modal \u2192 Single form or confirmation
2781
- \u251C\u2500 drawer \u2192 Detail view or quick edit form
2782
- \u2514\u2500 overlay \u2192 Confirmation dialog
2783
-
2784
- 3. What DOMAIN?
2785
- \u251C\u2500 business \u2192 entity-table + stats + filter-group
2786
- \u251C\u2500 dashboard \u2192 dashboard-grid + chart + stats
2787
- \u251C\u2500 ecommerce \u2192 entity-cards + stats (revenue)
2788
- \u251C\u2500 content \u2192 entity-cards + tabs + media
2789
- \u2514\u2500 workflow \u2192 timeline + progress-bar
2790
-
2791
- 4. What ENTITY FIELDS suggest?
2792
- \u251C\u2500 enum fields \u2192 filter-group, badge columns
2793
- \u251C\u2500 date fields \u2192 timeline, date columns
2794
- \u251C\u2500 number fields \u2192 stats, chart, meter
2795
- \u251C\u2500 relation fields \u2192 tabs for related collections
2796
- \u2514\u2500 image/url fields \u2192 entity-cards (visual)
2797
- \`\`\``;
2798
- }
2799
- function getLayoutCompositionGuide() {
2800
- return `## Layout Composition
2801
-
2802
- Use layout patterns to create structured, visually rich views.
2803
-
2804
- ### Stack (VStack / HStack)
2805
- \`{ "type": "stack", "direction": "vertical"|"horizontal", "gap": "sm"|"md"|"lg", "children": [...] }\`
2806
-
2807
- ### Box (Styled Container)
2808
- \`{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md", "children": [...] }\`
2809
-
2810
- ### Grid (Multi-Column)
2811
- \`{ "type": "grid", "cols": 3, "gap": "md", "children": [...] }\`
2812
-
2813
- ### Composition Patterns
2814
-
2815
- **Page Layout** \u2014 VStack wrapping all content:
2816
- \`\`\`json
2817
- ["render-ui", "main", {
2818
- "type": "stack", "direction": "vertical", "gap": "lg",
2819
- "children": [
2820
- { "type": "page-header", "title": "...", "actions": [...] },
2821
- { "type": "stack", "direction": "horizontal", "gap": "md", "wrap": true,
2822
- "children": [
2823
- { "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
2824
- "children": [{ "type": "stats", "metrics": [...] }] },
2825
- { "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
2826
- "children": [{ "type": "stats", "metrics": [...] }] }
2827
- ]
2828
- },
2829
- { "type": "entity-table", "entity": "...", "columns": [...], "searchable": true }
2830
- ]
2831
- }]
2832
- \`\`\`
2833
-
2834
- **Dashboard Layout** \u2014 Grid of cards:
2835
- \`\`\`json
2836
- ["render-ui", "main", {
2837
- "type": "stack", "direction": "vertical", "gap": "lg",
2838
- "children": [
2839
- { "type": "page-header", "title": "Dashboard" },
2840
- { "type": "grid", "cols": { "sm": 1, "md": 2, "lg": 3 }, "gap": "md",
2841
- "children": [
2842
- { "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
2843
- "children": [{ "type": "stats", "metrics": [...] }] },
2844
- { "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
2845
- "children": [{ "type": "chart", "chartType": "line", "data": [...] }] },
2846
- { "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
2847
- "children": [{ "type": "entity-cards", "entity": "...", "columns": 1 }] }
2848
- ]
2849
- }
2850
- ]
2851
- }]
2852
- \`\`\`
2853
-
2854
- **Detail Drawer** \u2014 Stacked sections:
2855
- \`\`\`json
2856
- ["render-ui", "drawer", {
2857
- "type": "stack", "direction": "vertical", "gap": "md",
2858
- "children": [
2859
- { "type": "entity-detail", "entity": "...", "actions": [{ "label": "Edit", "event": "EDIT" }] },
2860
- { "type": "tabs", "tabs": [
2861
- { "label": "Related Items", "content": { "type": "entity-table", "entity": "..." } },
2862
- { "label": "Activity", "content": { "type": "timeline", "items": [...] } }
2863
- ]}
2864
- ]
2865
- }]
2866
- \`\`\`
2867
-
2868
- ### When to Use Layout vs Flat
2869
- - **Flat** (multiple render-ui calls): Simple pages, 2-3 patterns stacked vertically
2870
- - **Nested** (single render-ui with layout): Complex pages, side-by-side elements, cards with backgrounds, dashboard grids`;
2871
- }
2872
- function getOutputFormatSection() {
2873
- return `## Output Format
2874
-
2875
- Return ONLY a JSON array of render-ui effect tuples. No explanation, no markdown.
2876
-
2877
- ### Simple (multiple flat effects):
2878
- \`\`\`json
2879
- [
2880
- ["render-ui", "main", { "type": "page-header", "title": "...", "actions": [...] }],
2881
- ["render-ui", "main", { "type": "stats", "entity": "...", "metrics": [...] }],
2882
- ["render-ui", "main", { "type": "entity-table", "entity": "...", "columns": [...] }]
2883
- ]
2884
- \`\`\`
2885
-
2886
- ### Composed (single effect with layout nesting):
2887
- \`\`\`json
2888
- [
2889
- ["render-ui", "main", { "type": "stack", "direction": "vertical", "gap": "lg", "children": [...] }]
2890
- ]
2891
- \`\`\`
2892
-
2893
- ### Clear slot:
2894
- \`\`\`json
2895
- [
2896
- ["render-ui", "modal", null]
2897
- ]
2898
- \`\`\`
2899
-
2900
- ### Rules
2901
- 1. Return valid JSON array \u2014 nothing else
2902
- 2. Every effect must be \`["render-ui", slot, config]\`
2903
- 3. Use entity fields from the input for columns, form fields, stats
2904
- 4. Match domain vocabulary for labels (e.g., "Place Order" not "Create")
2905
- 5. Include \`itemActions\` on tables/cards with appropriate events
2906
- 6. Use \`searchable: true\` on tables for business domains
2907
- 7. For INIT transitions, ALWAYS compose multiple patterns (never just a table)
2908
- 8. For CREATE/EDIT, always include \`submitEvent\` and \`cancelEvent\` on form-section`;
2909
- }
2910
- function generateKflowDesignSkill() {
2911
- const frontmatter = {
2912
- name: "kflow-design",
2913
- description: "Design rich render-ui effects for orbital schema transitions. Focused on pattern selection, layout composition, and domain-aware UI authoring.",
2914
- allowedTools: ["Read", "Write", "Edit"],
2915
- version: "1.0.0"
2916
- };
2917
- const content = `# Render-UI Design Skill
2918
-
2919
- > Design rich, polished render-ui effects for orbital schema transitions.
2920
-
2921
- You are a UI design specialist for KFlow orbital schemas. Your job is to take a
2922
- transition context (state, event, entity, domain) and produce the best possible
2923
- render-ui effects using the full pattern catalog.
2924
-
2925
- **Your goal**: Every transition should produce UI that is visually rich, functionally
2926
- complete, and domain-appropriate. Never default to just "entity-table" \u2014 compose
2927
- layouts with headers, stats, filters, and appropriate patterns.
2928
-
2929
- ---
2930
-
2931
- ${getTransitionContextGuide()}
2932
-
2933
- ---
2934
-
2935
- ${getRenderUIDesignGuide()}
2936
-
2937
- ---
2938
-
2939
- ${getLayoutCompositionGuide()}
2940
-
2941
- ---
2942
-
2943
- ${getSExprQuickRef2()}
2944
-
2945
- ---
2946
-
2947
- ${getCommonErrorsSection("top6")}
2948
-
2949
- ---
2950
-
2951
- ${getOutputFormatSection()}
2952
- `;
2953
- return {
2954
- name: "kflow-design",
2955
- frontmatter,
2956
- content
2957
- };
2958
- }
2959
- function getDesignSkillStats() {
2960
- const skill = generateKflowDesignSkill();
2961
- return {
2962
- lines: skill.content.split("\n").length,
2963
- chars: skill.content.length
2964
- };
2965
- }
2966
3183
 
2967
3184
  // src/orbitals-skills-generators/lean/lean-orbital-generator.ts
2968
3185
  var LEAN_CORE_INSTRUCTIONS = `
@@ -3168,7 +3385,7 @@ The tools handle proper prompting, caching, and S-Expression syntax. Writing dir
3168
3385
  { "name": "TasksPage", "path": "/tasks", "viewType": "list", "isInitial": true }
3169
3386
  ],
3170
3387
  "traits": ["TaskManager"],
3171
- "patterns": ["page-header", "entity-table", "form-section", "entity-detail"]
3388
+ "patterns": ["page-header", "entity-table", "form-section", "detail-panel"]
3172
3389
  }
3173
3390
  \`\`\`
3174
3391
 
@@ -3265,7 +3482,7 @@ TaskManager behavior:
3265
3482
  then ["render-ui", "modal", null]
3266
3483
 
3267
3484
  - From Browsing to Viewing on VIEW
3268
- then ["render-ui", "drawer", {"type": "entity-detail", "entity": "Task", "fieldNames": ["title", "description", "status", "priority", "dueDate"], "actions": [{"label": "Edit", "event": "EDIT"}, {"label": "Delete", "event": "DELETE", "variant": "danger"}]}]
3485
+ then ["render-ui", "drawer", {"type": "detail-panel", "entity": "Task", "fields": ["title", "description", "status", "priority", "dueDate"], "actions": [{"label": "Edit", "event": "EDIT"}, {"label": "Delete", "event": "DELETE", "variant": "danger"}]}]
3269
3486
 
3270
3487
  - From Viewing to Editing on EDIT
3271
3488
  then ["render-ui", "drawer", null]
@@ -3559,10 +3776,139 @@ function generateAllBuilderSkills() {
3559
3776
  },
3560
3777
  content: generateLeanFixingSkill2()
3561
3778
  },
3562
- generateDomainLanguageSkill(),
3563
- generateKflowDesignSkill()
3779
+ generateDomainLanguageSkill()
3564
3780
  ];
3565
3781
  }
3782
+ function getMinimalTypeReference() {
3783
+ return `
3784
+ ## Orbital Schema Structure
3785
+
3786
+ \`\`\`typescript
3787
+ interface OrbitalDefinition {
3788
+ name: string; // Entity name (PascalCase)
3789
+ entity: Entity; // Data model
3790
+ traits: TraitRef[]; // State machines (names or definitions)
3791
+ pages: Page[]; // Routes and views
3792
+ emits?: string[]; // Events this orbital emits
3793
+ listens?: EventListener[]; // Events this orbital listens to
3794
+ }
3795
+ \`\`\`
3796
+
3797
+ ### Entity Fields
3798
+
3799
+ \`\`\`typescript
3800
+ { name: "title", type: "string", required: true }
3801
+ { name: "count", type: "number", default: 0 }
3802
+ { name: "status", type: "enum", values: ["pending", "active", "done"] }
3803
+ { name: "dueDate", type: "date" }
3804
+ \`\`\`
3805
+
3806
+ ### Trait State Machine
3807
+
3808
+ \`\`\`typescript
3809
+ {
3810
+ states: [{ name: "Idle", isInitial: true }, { name: "Active" }],
3811
+ events: ["INIT", "ACTIVATE", "COMPLETE"],
3812
+ transitions: [
3813
+ { from: "Idle", to: "Active", event: "ACTIVATE",
3814
+ guards: [["condition"]],
3815
+ effects: [["action"]] }
3816
+ ]
3817
+ }
3818
+ \`\`\`
3819
+ `.trim();
3820
+ }
3821
+ function getPatternTypesCompact() {
3822
+ const patterns = getAllPatternTypes();
3823
+ return `
3824
+ ## Available Pattern Types
3825
+
3826
+ ${patterns.map((p) => `- \`${p}\``).join("\n")}
3827
+
3828
+ ${getPatternPropsCompact()}
3829
+ `.trim();
3830
+ }
3831
+ function getSExprQuickRef2() {
3832
+ const operators = Object.keys(OPERATORS).slice(0, 15);
3833
+ return `
3834
+ ## S-Expression Quick Reference
3835
+
3836
+ ### Guard Expressions (Conditions)
3837
+
3838
+ \`\`\`typescript
3839
+ ["=", "@entity.status", "active"] // Equality
3840
+ [">", "@entity.count", 0] // Greater than
3841
+ ["and", ["cond1"], ["cond2"]] // Logical AND
3842
+ ["or", ["cond1"], ["cond2"]] // Logical OR
3843
+ ["not", ["condition"]] // Logical NOT
3844
+ \`\`\`
3845
+
3846
+ ### Effect Expressions (Actions)
3847
+
3848
+ \`\`\`typescript
3849
+ ["set", "@entity.field", value] // Update field
3850
+ ["emit", "EVENT_NAME", payload] // Emit event
3851
+ ["navigate", "/path"] // Navigate to route
3852
+ ["render-ui", "main", { type, props }] // Render pattern
3853
+ ["persist", "create", "Entity", data] // Database operation
3854
+ \`\`\`
3855
+
3856
+ ### Available Operators
3857
+
3858
+ ${operators.map((op) => `- \`${op}\``).join("\n")}
3859
+ `.trim();
3860
+ }
3861
+ function getRenderUIQuickRef2() {
3862
+ const slots = UI_SLOTS;
3863
+ return `
3864
+ ## Render-UI Effect Reference
3865
+
3866
+ ### Syntax
3867
+
3868
+ \`\`\`typescript
3869
+ ["render-ui", slot, patternConfig | null]
3870
+ \`\`\`
3871
+
3872
+ ### UI Slots
3873
+
3874
+ ${slots.map((slot) => `- \`${slot}\``).join("\n")}
3875
+
3876
+ ### Example
3877
+
3878
+ \`\`\`typescript
3879
+ ["render-ui", "main", {
3880
+ type: "entity-table",
3881
+ entity: "Task",
3882
+ columns: ["title", "status"],
3883
+ itemActions: [{ label: "Edit", event: "EDIT" }]
3884
+ }]
3885
+ \`\`\`
3886
+
3887
+ Clear slot: \`["render-ui", "modal", null]\`
3888
+ `.trim();
3889
+ }
3890
+ function getFieldTypesCompact() {
3891
+ return `
3892
+ ## Field Types
3893
+
3894
+ | Type | Example | Notes |
3895
+ |------|---------|-------|
3896
+ | \`string\` | \`{ name: "title", type: "string" }\` | Text |
3897
+ | \`number\` | \`{ name: "count", type: "number" }\` | Integer or float |
3898
+ | \`boolean\` | \`{ name: "active", type: "boolean" }\` | true/false |
3899
+ | \`date\` | \`{ name: "birthday", type: "date" }\` | Date only |
3900
+ | \`timestamp\` | \`{ name: "createdAt", type: "timestamp" }\` | Date + time |
3901
+ | \`enum\` | \`{ name: "status", type: "enum", values: ["a", "b"] }\` | Fixed options |
3902
+ | \`array\` | \`{ name: "tags", type: "array", items: "string" }\` | List |
3903
+ | \`relation\` | \`{ name: "user", type: "relation", relation: { entity: "User", cardinality: "one" } }\` | Foreign key |
3904
+
3905
+ ### Field Properties
3906
+
3907
+ - \`required: true\` - Must have value
3908
+ - \`default: value\` - Default value
3909
+ - \`unique: true\` - Must be unique
3910
+ `.trim();
3911
+ }
3566
3912
 
3567
3913
  // src/prompts/generation-prompts.ts
3568
3914
  function getOrbitalDecompositionPrompt() {
@@ -3736,6 +4082,316 @@ Use with: \`uses: [{ from: "std/behaviors/crud", as: "CRUD" }]\`
3736
4082
  `;
3737
4083
  }
3738
4084
 
3739
- export { formatFrontmatter, generateAllBuilderSkills, generateDomainLanguageSkill, generateKflowDesignSkill, generateKflowOrbitalFixingSkill, generateKflowOrbitalsSkill, generateLeanFixingSkill2 as generateLeanFixingSkill, generateLeanFixingSkill as generateLeanFixingSkillFull, generateLeanOrbitalSkill2 as generateLeanOrbitalSkill, generateLeanOrbitalSkill as generateLeanOrbitalSkillFull, getArchitectureSection, getAssetRefSection, getCommonErrorsSection, getCommonFixPatternsSection, getCompletionRulesSection, getConnectivityCompact, getContextUsageCompact, getContextUsageSection, getCustomTraitCompact, getCustomTraitSection, getDecompositionChecklist, getDecompositionCompact, getDecompositionSection, getDesignErrorsCompact, getDesignErrorsSection, getDesignSkillStats, getEfficiencySection, getFieldTypesCompact, getFixingWorkflowSection, getFlowPatternSection, getFullOrbitalPrompt, getGameAsOrbitalsSection, getGameEntityTemplatesSection, getGamePatternsSection, getGameTraitsSection, getGameTypesSection, getIconLibraryCompact, getIconLibrarySection, getKeyBehaviorsReference2 as getKeyBehaviorsReference, getMinimalTypeReference, getMultiFileSection, getOrbitalConnectivitySection, getOrbitalDecompositionPrompt, getOverGenerationSection, getPatternTypesCompact, getPortableOrbitalOutputSection, getRenderUIDesignGuide, getRenderUIQuickRef2 as getRenderUIQuickRef, getRequirementsDecomposePrompt, getRequirementsTraitPrompt, getSExprQuickRef2 as getSExprQuickRef, getSchemaUpdateCompact, getSchemaUpdateSection, getUsesImportCompact, getUsesImportSection, getValidationHintsSection, writeAllSkills, writeSkill };
4085
+ // src/evals/composition-quality.ts
4086
+ var EVAL_CASES = [
4087
+ {
4088
+ name: "task-management-basic",
4089
+ description: "Generate a basic task management view with CRUD",
4090
+ prompt: `Generate an Orbital schema for a task management app.
4091
+
4092
+ Entity: Task with fields: title (string, required), status (enum: pending/active/done), priority (enum: low/medium/high)
4093
+
4094
+ Requirements:
4095
+ - List view with search and actions (view, edit, delete)
4096
+ - Modal form for creating tasks
4097
+ - Use atomic composition with stack layouts
4098
+ - Include stats/overview section showing counts`,
4099
+ expectedPatterns: ["stack", "page-header", "entity-table", "form-section", "box", "typography", "badge", "button"],
4100
+ minScore: 70,
4101
+ domain: "general"
4102
+ },
4103
+ {
4104
+ name: "patient-portal-dashboard",
4105
+ description: "Generate a healthcare patient portal dashboard",
4106
+ prompt: `Generate an Orbital schema for a healthcare patient portal.
4107
+
4108
+ Entities:
4109
+ - Patient: name, dateOfBirth, medicalRecordNumber, insuranceStatus
4110
+ - Appointment: date, time, doctor, status, notes
4111
+
4112
+ Requirements:
4113
+ - Dashboard with patient statistics (total, active, critical)
4114
+ - Patient list with filters by status
4115
+ - Appointment scheduling view
4116
+ - Use healthcare-appropriate layouts (calm, organized)
4117
+ - Include tabs for different views`,
4118
+ expectedPatterns: ["stack", "grid", "page-header", "entity-table", "tabs", "badge", "card", "stats"],
4119
+ minScore: 75,
4120
+ domain: "healthcare"
4121
+ },
4122
+ {
4123
+ name: "ecommerce-product-catalog",
4124
+ description: "Generate an e-commerce product catalog",
4125
+ prompt: `Generate an Orbital schema for an e-commerce product catalog.
4126
+
4127
+ Entities:
4128
+ - Product: name, price, category, stockLevel, rating, imageUrl
4129
+ - Category: name, description
4130
+
4131
+ Requirements:
4132
+ - Product grid with cards (use grid layout)
4133
+ - Filters by category and price range
4134
+ - Product detail view with image
4135
+ - Shopping cart indicator
4136
+ - Use product-appropriate layouts (visual, appealing)`,
4137
+ expectedPatterns: ["stack", "grid", "entity-cards", "filter-group", "badge", "card", "image"],
4138
+ minScore: 75,
4139
+ domain: "ecommerce"
4140
+ },
4141
+ {
4142
+ name: "project-management-kanban",
4143
+ description: "Generate a project management kanban board",
4144
+ prompt: `Generate an Orbital schema for a project management kanban board.
4145
+
4146
+ Entities:
4147
+ - Project: name, status, deadline, progress, owner
4148
+ - Task: title, status (todo/in-progress/done), assignee, priority, dueDate
4149
+
4150
+ Requirements:
4151
+ - Kanban board with columns for each status
4152
+ - Task cards with drag-drop feel (visual design)
4153
+ - Project overview with progress bars
4154
+ - Team member avatars
4155
+ - Due date indicators`,
4156
+ expectedPatterns: ["stack", "grid", "card", "progress-bar", "avatar", "badge", "page-header"],
4157
+ minScore: 80,
4158
+ domain: "project-management"
4159
+ },
4160
+ {
4161
+ name: "analytics-dashboard",
4162
+ description: "Generate an analytics dashboard with charts",
4163
+ prompt: `Generate an Orbital schema for an analytics dashboard.
4164
+
4165
+ Entities:
4166
+ - Metric: name, value, change, trend
4167
+ - Report: title, date, type, status
4168
+
4169
+ Requirements:
4170
+ - Stats cards with trend indicators (up/down)
4171
+ - Chart visualization area
4172
+ - Recent reports list
4173
+ - Date range selector
4174
+ - Professional, data-dense layout`,
4175
+ expectedPatterns: ["stack", "grid", "stats", "chart", "entity-table", "badge", "card"],
4176
+ minScore: 75,
4177
+ domain: "general"
4178
+ }
4179
+ ];
4180
+ function analyzeComposition(schema) {
4181
+ const metrics = {
4182
+ renderUICount: 0,
4183
+ atomTypes: [],
4184
+ moleculeTypes: [],
4185
+ organismTypes: [],
4186
+ layoutRoot: null,
4187
+ nestingDepth: 0,
4188
+ sectionCount: 0,
4189
+ themeVariableUsage: 0,
4190
+ hardcodedValues: []
4191
+ };
4192
+ for (const orbital of schema.orbitals) {
4193
+ for (const trait of orbital.traits) {
4194
+ const t = trait;
4195
+ if (!t.stateMachine?.transitions) continue;
4196
+ for (const transition of t.stateMachine.transitions) {
4197
+ if (!transition.effects) continue;
4198
+ for (const effect of transition.effects) {
4199
+ if (!Array.isArray(effect)) continue;
4200
+ if (effect[0] !== "render-ui") continue;
4201
+ metrics.renderUICount++;
4202
+ const pattern = effect[2];
4203
+ if (pattern && typeof pattern === "object") {
4204
+ analyzePattern(pattern, metrics, 0);
4205
+ }
4206
+ }
4207
+ }
4208
+ }
4209
+ }
4210
+ const totalValues = metrics.atomTypes.length + metrics.moleculeTypes.length + metrics.organismTypes.length;
4211
+ if (totalValues > 0) {
4212
+ metrics.themeVariableUsage = 100 - metrics.hardcodedValues.length / totalValues * 100;
4213
+ }
4214
+ return metrics;
4215
+ }
4216
+ function analyzePattern(pattern, metrics, depth) {
4217
+ if (!pattern || typeof pattern !== "object") return;
4218
+ metrics.nestingDepth = Math.max(metrics.nestingDepth, depth);
4219
+ if (depth === 0 && ["stack", "box", "container", "grid"].includes(pattern.type)) {
4220
+ metrics.layoutRoot = pattern.type;
4221
+ }
4222
+ const atomTypes = ["typography", "badge", "button", "avatar", "icon", "progress-bar", "divider"];
4223
+ const moleculeTypes = ["card", "modal", "drawer", "tabs", "alert", "accordion", "box"];
4224
+ const organismTypes = ["entity-table", "form-section", "detail-panel", "page-header", "chart", "timeline", "stats"];
4225
+ if (atomTypes.includes(pattern.type) && !metrics.atomTypes.includes(pattern.type)) {
4226
+ metrics.atomTypes.push(pattern.type);
4227
+ }
4228
+ if (moleculeTypes.includes(pattern.type) && !metrics.moleculeTypes.includes(pattern.type)) {
4229
+ metrics.moleculeTypes.push(pattern.type);
4230
+ }
4231
+ if (organismTypes.includes(pattern.type) && !metrics.organismTypes.includes(pattern.type)) {
4232
+ metrics.organismTypes.push(pattern.type);
4233
+ }
4234
+ for (const [key, value] of Object.entries(pattern)) {
4235
+ if (typeof value === "string") {
4236
+ if (value.startsWith("#") || /^\d+px$/.test(value) || ["white", "black", "red", "blue"].includes(value.toLowerCase())) {
4237
+ metrics.hardcodedValues.push(`${key}: ${value}`);
4238
+ }
4239
+ }
4240
+ }
4241
+ if (depth === 1 && pattern.type) {
4242
+ metrics.sectionCount++;
4243
+ }
4244
+ if (pattern.children && Array.isArray(pattern.children)) {
4245
+ for (const child of pattern.children) {
4246
+ analyzePattern(child, metrics, depth + 1);
4247
+ }
4248
+ }
4249
+ }
4250
+ function scoreStructure(metrics, schema) {
4251
+ let score = 0;
4252
+ const transitions = countTransitions(schema);
4253
+ if (metrics.renderUICount <= transitions) {
4254
+ score += 5;
4255
+ }
4256
+ if (metrics.layoutRoot) {
4257
+ score += 5;
4258
+ }
4259
+ if (metrics.nestingDepth >= 3) {
4260
+ score += 5;
4261
+ } else if (metrics.nestingDepth >= 2) {
4262
+ score += 3;
4263
+ }
4264
+ score += 5;
4265
+ if (hasClosedCircuit(schema)) {
4266
+ score += 5;
4267
+ }
4268
+ return Math.min(25, score);
4269
+ }
4270
+ function scoreComposition(metrics) {
4271
+ let score = 0;
4272
+ if (metrics.atomTypes.length >= 4) {
4273
+ score += 10;
4274
+ } else if (metrics.atomTypes.length === 3) {
4275
+ score += 7;
4276
+ } else if (metrics.atomTypes.length === 2) {
4277
+ score += 5;
4278
+ }
4279
+ if (metrics.moleculeTypes.length >= 3) {
4280
+ score += 7;
4281
+ } else if (metrics.moleculeTypes.length === 2) {
4282
+ score += 5;
4283
+ } else if (metrics.moleculeTypes.length === 1) {
4284
+ score += 3;
4285
+ }
4286
+ if (metrics.organismTypes.length >= 2) {
4287
+ score += 8;
4288
+ } else if (metrics.organismTypes.length === 1) {
4289
+ score += 5;
4290
+ }
4291
+ return Math.min(25, score);
4292
+ }
4293
+ function scoreTheme(metrics) {
4294
+ let score = 0;
4295
+ if (metrics.themeVariableUsage >= 95) {
4296
+ score += 15;
4297
+ } else if (metrics.themeVariableUsage >= 85) {
4298
+ score += 10;
4299
+ } else if (metrics.themeVariableUsage >= 75) {
4300
+ score += 5;
4301
+ }
4302
+ const hasNoHardcodedColors = !metrics.hardcodedValues.some((v) => v.includes("#") || ["white", "black"].some((c) => v.toLowerCase().includes(c)));
4303
+ if (hasNoHardcodedColors) {
4304
+ score += 5;
4305
+ }
4306
+ const hasNoHardcodedSpacing = !metrics.hardcodedValues.some((v) => /\d+px/.test(v));
4307
+ if (hasNoHardcodedSpacing) {
4308
+ score += 5;
4309
+ }
4310
+ return Math.min(25, score);
4311
+ }
4312
+ function scoreQuality(metrics, testCase) {
4313
+ let score = 0;
4314
+ if (metrics.sectionCount >= 4) {
4315
+ score += 8;
4316
+ } else if (metrics.sectionCount === 3) {
4317
+ score += 6;
4318
+ } else if (metrics.sectionCount === 2) {
4319
+ score += 4;
4320
+ }
4321
+ const expectedPresent = testCase.expectedPatterns.filter(
4322
+ (p) => metrics.atomTypes.includes(p) || metrics.moleculeTypes.includes(p) || metrics.organismTypes.includes(p)
4323
+ ).length;
4324
+ score += expectedPresent / testCase.expectedPatterns.length * 8;
4325
+ score += 5;
4326
+ score += 4;
4327
+ return Math.min(25, score);
4328
+ }
4329
+ function calculateTotalScore(schema, testCase, validationErrors) {
4330
+ const metrics = analyzeComposition(schema);
4331
+ const breakdown = {
4332
+ structure: scoreStructure(metrics, schema),
4333
+ composition: scoreComposition(metrics),
4334
+ theme: scoreTheme(metrics),
4335
+ quality: scoreQuality(metrics, testCase)
4336
+ };
4337
+ if (validationErrors.length > 0) {
4338
+ breakdown.structure = Math.max(0, breakdown.structure - validationErrors.length * 2);
4339
+ }
4340
+ const total = breakdown.structure + breakdown.composition + breakdown.theme + breakdown.quality;
4341
+ return {
4342
+ score: Math.min(100, Math.round(total)),
4343
+ breakdown
4344
+ };
4345
+ }
4346
+ function countTransitions(schema) {
4347
+ let count = 0;
4348
+ for (const orbital of schema.orbitals) {
4349
+ for (const trait of orbital.traits) {
4350
+ const t = trait;
4351
+ if (t.stateMachine?.transitions) {
4352
+ count += t.stateMachine.transitions.length;
4353
+ }
4354
+ }
4355
+ }
4356
+ return count;
4357
+ }
4358
+ function hasClosedCircuit(schema) {
4359
+ for (const orbital of schema.orbitals) {
4360
+ for (const trait of orbital.traits) {
4361
+ const t = trait;
4362
+ if (!t.stateMachine) continue;
4363
+ const states = new Set((t.stateMachine.states || []).map((s) => s.name));
4364
+ const incomingStates = /* @__PURE__ */ new Set();
4365
+ const outgoingStates = /* @__PURE__ */ new Set();
4366
+ for (const transition of t.stateMachine.transitions || []) {
4367
+ incomingStates.add(transition.to);
4368
+ outgoingStates.add(transition.from);
4369
+ }
4370
+ for (const state of states) {
4371
+ const stateObj = (t.stateMachine.states || []).find((s) => s.name === state);
4372
+ if (!stateObj?.isInitial && !incomingStates.has(state)) {
4373
+ return false;
4374
+ }
4375
+ }
4376
+ }
4377
+ }
4378
+ return true;
4379
+ }
4380
+ function generateComparisonMatrix(comparisons) {
4381
+ let markdown = "# Composition Quality Provider Comparison\n\n";
4382
+ markdown += "| Provider | Average Score | task-mgmt | patient | ecommerce | kanban | analytics |\n";
4383
+ markdown += "|----------|---------------|-----------|---------|-----------|--------|-----------|\n";
4384
+ for (const comp of comparisons) {
4385
+ const scores = EVAL_CASES.map((tc) => {
4386
+ const result = comp.cases.find((c) => c.caseName === tc.name);
4387
+ return result ? `${result.score}${result.passed ? "\u2713" : ""}` : "N/A";
4388
+ });
4389
+ markdown += `| ${comp.provider} | ${comp.averageScore} | ${scores.join(" | ")} |
4390
+ `;
4391
+ }
4392
+ return markdown;
4393
+ }
4394
+
4395
+ export { EVAL_CASES, analyzeComposition, calculateTotalScore, formatFrontmatter, generateAllBuilderSkills, generateComparisonMatrix, generateDomainLanguageSkill, generateKflowOrbitalFixingSkill, generateKflowOrbitalsSkill, generateLeanFixingSkill2 as generateLeanFixingSkill, generateLeanFixingSkill as generateLeanFixingSkillFull, generateLeanOrbitalSkill2 as generateLeanOrbitalSkill, generateLeanOrbitalSkill as generateLeanOrbitalSkillFull, getArchitectureSection, getAssetRefSection, getBannedProps, getBindingContextRules, getBindingsCompact, getBindingsGuide, getCommonErrorsSection, getCommonFixPatternsSection, getCompletionRulesSection, getConnectivityCompact, getContextUsageCompact, getContextUsageSection, getCustomTraitCompact, getCustomTraitSection, getDecompositionChecklist, getDecompositionCompact, getDecompositionSection, getDesignErrorsCompact, getDesignErrorsSection, getEfficiencySection, getFieldTypesCompact, getFixingWorkflowSection, getFlowPatternSection, getFullOrbitalPrompt, getGameAsOrbitalsSection, getGameEntityTemplatesSection, getGamePatternsSection, getGameTraitsSection, getGameTypesSection, getIconLibraryCompact, getIconLibrarySection, getKeyBehaviorsReference2 as getKeyBehaviorsReference, getMinimalTypeReference, getMultiFileSection, getOrbitalConnectivitySection, getOrbitalDecompositionPrompt, getOverGenerationSection, getPatternTypesCompact, getPortableOrbitalOutputSection, getRenderUIDesignGuide, getRenderUIQuickRef2 as getRenderUIQuickRef, getRequirementsDecomposePrompt, getRequirementsTraitPrompt, getSExprQuickRef2 as getSExprQuickRef, getSchemaUpdateCompact, getSchemaUpdateSection, getThemeGuide, getUsesImportCompact, getUsesImportSection, getValidationHintsSection, writeAllSkills, writeSkill };
3740
4396
  //# sourceMappingURL=index.js.map
3741
4397
  //# sourceMappingURL=index.js.map