unoverse 0.1.187 → 0.1.189

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unoverse",
3
- "version": "0.1.187",
3
+ "version": "0.1.189",
4
4
  "description": "The Unoverse front door — create a Studio project, a universe, or a client app, and launch Studio.",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",
@@ -399,8 +399,16 @@ function lintFile(file) {
399
399
  // ONE REQUIREMENT SHAPE (2026-08-29): a kind declares its tree (`states:`) OR
400
400
  // its drawing (`root` — flat components/atoms). A tree component's root is
401
401
  // SYNTHESIZED by the compiler, never required.
402
+ // A BLOCK is a template that declares a DRAWING instead of a tree (2026-08-31): a flat
403
+ // file, no manifest, one `root:` — `pair`, `feature`, `single`, `rail`, `stack`. It has
404
+ // no states because it is not a screen: it is a shape a page imports by `Ref`, inlined
405
+ // before the page's sections compile. Requiring `states:` of it would be demanding a
406
+ // state machine from a fragment, which is the same mistake as demanding a manifest:
407
+ // both are what a PAGE has, and a block is not a page.
408
+ const isBlock = declared === "template" && json.states === undefined && json.root !== undefined;
402
409
  const envelopeRequired =
403
- declared === "app" || declared === "template" ? ["name", "states"]
410
+ isBlock ? ["name", "root"]
411
+ : declared === "app" || declared === "template" ? ["name", "states"]
404
412
  : declared === "component" ? ["name", ...(json.states !== undefined || json.state?.view !== undefined ? [] : ["root"])]
405
413
  : ["name", "root"];
406
414
  if (declared === "template" && json.states === undefined && (json.parts !== undefined || json.shapes !== undefined)) envelopeRequired.pop();
@@ -45,7 +45,7 @@ export const UNIVERSAL_PROPS = new Set([
45
45
  */
46
46
  export const PROP_KEYS = [
47
47
  "type", "input", "description", "maxLength", "minItems", "maxItems",
48
- "hydrate", "optional", "enum", "preview", "default", "items",
48
+ "hydrate", "override", "optional", "enum", "preview", "default", "items",
49
49
  ];
50
50
 
51
51
  /**
@@ -86,7 +86,7 @@ export const PRIMITIVE_PROPS = {
86
86
  Input: ["placeholder", "inputType", "disabledWhen", "maxLength", "multiline", "rows",
87
87
  "inputMode", "autoComplete", "advanceOnFill"],
88
88
  Select: ["placeholder", "options", "disabledWhen"],
89
- Each: ["template", "app", "items"],
89
+ Each: ["item", "app", "items"],
90
90
  Switch: ["on", "cases", "fallback"],
91
91
  Ref: ["ref", "props", "with", "children", "name"],
92
92
  ComponentSlot: ["select", "frame", "fallback", "pinned", "appWidth"],
@@ -121,7 +121,7 @@ export const STYLE_KEYS = new Set([
121
121
  // exact regex from server/src/runtime/definition-tokens.test.ts
122
122
  export const RAW_VALUE = /#[0-9a-fA-F]{3,8}\b|\b\d*\.?\d+(px|rem|em)\b/;
123
123
  // nodes reachable through these keys (data keys like `items`/`cases` handled explicitly)
124
- export const CHILD_NODE_KEYS = ["children", "template", "fallback", "user", "assistant"];
124
+ export const CHILD_NODE_KEYS = ["children", "item", "fallback", "user", "assistant"];
125
125
  // folders that hold BARE PARTIALS one level under the definition root
126
126
  export const PARTIAL_DIRS = new Set(["layouts", "states", "components", "blocks"]);
127
127
 
@@ -68,16 +68,19 @@ function walkNode(node, file, root, widthCap = null, isLayoutRoot = false) {
68
68
  report("error", file, `director.preview names unknown component "${c}". No match in the design system or this org's components (lookup is case-insensitive)`);
69
69
  }
70
70
  }
71
- // ONE MIND, MANY BANDS9b rule 3, amended 2026-08-30): a layout may hold several
72
- // directed bands — one verdict, arranged — but each must claim a DISTINCT face, or
73
- // the surface is ambiguous (the reaction contract's one-view-one-surface rule). So
74
- // on a multi-band layout every director declares its `state:`; two bands claiming
75
- // the same face is the error this rule now exists for.
71
+ // A PLACE NEEDS NO NAME 9d, ruled 2026-08-31). A layout may hold several director
72
+ // places — one mind, arranged — and each needs a DISTINCT address or the surface is
73
+ // ambiguous (the reaction contract's one-view-one-surface rule). But the ADDRESS is
74
+ // the compiler's to hand out, by position, and an author writes places and a brief,
75
+ // never a face name. This rule used to demand `state:` on every place after the
76
+ // first; that was config in the layout, saying nothing the one mind did not already
77
+ // know from the page's brief.
78
+ //
79
+ // An AUTHORED `state:` still stands (the flat-email pin, §9b rule 4), so two places
80
+ // pinned to the SAME face remains an error — that one is genuinely ambiguous.
76
81
  const seen = directorsSeen.get(file) ?? [];
77
82
  const face = typeof d?.state === "string" ? d.state : null;
78
- if (seen.length && !face)
79
- report("error", file, `a second "director:" in this layout declares no "state:". Several bands are allowed — one mind, arranged — but each must claim a DISTINCT face, so every one of them names it (§9b rule 3)`);
80
- else if (face && seen.includes(face))
83
+ if (face && seen.includes(face))
81
84
  report("error", file, `two directed bands claim the face "${face}". A face has exactly one surface, or the active one is ambiguous (§9b rule 3, the reaction contract)`);
82
85
  directorsSeen.set(file, [...seen, face]);
83
86
  } else if (typeof node[word] !== "string") {
@@ -151,12 +154,12 @@ function walkNode(node, file, root, widthCap = null, isLayoutRoot = false) {
151
154
  report("error", file, `Switch on "${node.on}" → case "${caseKey}" re-guards its own discriminant. A layer never guards itself; delete the visibleWhen (docs.unoverse.ai/design/components)`);
152
155
  }
153
156
  }
154
- // Each: a `template` + a list — EITHER a literal `items:[]` (hardcoded content,
157
+ // Each: an `item` + a list — EITHER a literal `items:[]` (hardcoded content,
155
158
  // the microapp default) OR `bind.items` (a workflow-fed array).
156
159
  if (t === "Each") {
157
160
  const hasList = Array.isArray(node.items) || (node.bind && typeof node.bind === "object" && node.bind.items);
158
- if (!node.template || !hasList)
159
- report("error", file, `Each needs "template" + a list. Literal "items": [...] or "bind": { "items": "<field>" } (docs.unoverse.ai/design/components)`);
161
+ if (!node.item || !hasList)
162
+ report("error", file, `Each needs "item" + a list. Literal "items": [...] or "bind": { "items": "<field>" } (docs.unoverse.ai/design/components)`);
160
163
  }
161
164
  if (t === "Ref") {
162
165
  if (typeof node.ref !== "string")