@decantr/essence-spec 1.0.0-beta.9 → 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Decantr AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # @decantr/essence-spec
2
+
3
+ Support status: `core-supported`
4
+ Release channel: `stable`
5
+
6
+ Schemas, validation, migration, guard evaluation, and TypeScript types for `decantr.essence.json`.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @decantr/essence-spec
12
+ ```
13
+
14
+ ## What It Exports
15
+
16
+ - `validateEssence()` for schema validation
17
+ - `evaluateGuard()` for contract/guard checks
18
+ - `normalizeEssence()` for version normalization
19
+ - `migrateV2ToV3()` and `migrateV30ToV31()` for structured migrations
20
+ - Decantr essence TypeScript types
21
+
22
+ ## Example
23
+
24
+ ```ts
25
+ import { evaluateGuard, validateEssence } from '@decantr/essence-spec';
26
+
27
+ const result = validateEssence(essence);
28
+ if (!result.valid) {
29
+ console.error(result.errors);
30
+ }
31
+
32
+ const violations = evaluateGuard(essence, {});
33
+ ```
34
+
35
+ ## Schema Exports
36
+
37
+ - `@decantr/essence-spec/schema/essence.v2.json`
38
+ - `@decantr/essence-spec/schema/essence.v3.json`
39
+
40
+ ## Compatibility
41
+
42
+ `@decantr/essence-spec` now defines a stable public contract for Decantr essence validation and migration in the `1.x` line.
43
+
44
+ - additive schema fields may be introduced in compatible minor releases
45
+ - breaking schema or migration behavior changes require a major version
46
+ - deprecation and migration guidance should be documented before removing or replacing a supported essence path
47
+
48
+ ## Stability Note
49
+
50
+ This package is the lowest-level public Decantr contract and is intended to remain boring and dependable for downstream consumers.
51
+
52
+ - patch releases should stay documentation-only or behaviorally compatible
53
+ - schema export paths are part of the supported public surface
54
+ - coordinated downstream releases should only be needed when a package explicitly adopts a newer essence-spec version
55
+
56
+ ## License
57
+
58
+ MIT
package/dist/index.d.ts CHANGED
@@ -11,13 +11,12 @@ type ThemeStyle = 'auradecantism' | 'clean' | 'glassmorphism' | 'retro' | 'biolu
11
11
  type ThemeMode = 'light' | 'dark' | 'auto';
12
12
  type ThemeShape = 'sharp' | 'rounded' | 'pill';
13
13
  interface Theme {
14
- style: ThemeStyle | string;
14
+ id: string;
15
15
  mode: ThemeMode;
16
- recipe: string;
17
16
  shape?: ThemeShape;
18
17
  }
19
18
  type PlatformType = 'spa' | 'ssr' | 'static';
20
- type RoutingStrategy = 'hash' | 'history';
19
+ type RoutingStrategy = 'hash' | 'history' | 'pathname';
21
20
  interface Platform {
22
21
  type: PlatformType;
23
22
  routing: RoutingStrategy;
@@ -58,11 +57,25 @@ interface SpatialTokens {
58
57
  '--d-data-py': string;
59
58
  '--d-control-py': string;
60
59
  '--d-content-gap': string;
60
+ '--d-label-mb': string;
61
+ '--d-label-px': string;
62
+ '--d-section-gap': string;
63
+ '--d-annotation-mt': string;
64
+ }
65
+ interface SpatialTokenHints {
66
+ section_padding?: string | null;
67
+ density_bias?: number;
68
+ content_gap_shift?: number;
69
+ label_content_gap?: string | null;
70
+ }
71
+ interface ShellGuidance {
72
+ section_label_treatment?: string;
73
+ section_density?: DensityLevel;
74
+ [key: string]: string | DensityLevel | undefined;
61
75
  }
62
76
  type GuardMode = 'creative' | 'guided' | 'strict';
63
77
  interface Guard {
64
78
  enforce_style?: boolean;
65
- enforce_recipe?: boolean;
66
79
  mode: GuardMode;
67
80
  }
68
81
  interface Impression {
@@ -163,7 +176,7 @@ interface EssenceDNA {
163
176
  effects?: Record<string, string>;
164
177
  };
165
178
  }
166
- /** Only density and mode may be overridden per-page. DNA axioms like wcag_level and theme.style are never overrideable. */
179
+ /** Only density and mode may be overridden per-page. DNA axioms like wcag_level and theme.id are never overrideable. */
167
180
  interface DNAOverrides {
168
181
  density?: DensityLevel;
169
182
  mode?: ThemeMode;
@@ -245,24 +258,19 @@ interface ValidationResult {
245
258
  }
246
259
  declare function validateEssence(data: unknown): ValidationResult;
247
260
 
248
- interface RecipeSpatialHints {
249
- density_bias?: number;
250
- content_gap_shift?: number;
251
- }
252
- declare function computeDensity(personality: string[], recipeSpatial?: RecipeSpatialHints): Density;
253
- interface SpatialRecipeHints {
254
- section_padding?: string | null;
261
+ interface SpatialHints {
255
262
  density_bias?: number;
256
263
  content_gap_shift?: number;
257
264
  }
258
- declare function computeSpatialTokens(density: DensityLevel, recipeHints?: SpatialRecipeHints): SpatialTokens;
265
+ declare function computeDensity(personality: string[], spatialHints?: SpatialHints): Density;
266
+ declare function computeSpatialTokens(density: DensityLevel, spatialHints?: SpatialTokenHints): SpatialTokens;
259
267
 
260
268
  interface AutoFix {
261
269
  type: 'add_page' | 'update_layout' | 'update_blueprint';
262
270
  patch: Record<string, unknown>;
263
271
  }
264
272
  interface GuardViolation {
265
- rule: 'style' | 'structure' | 'layout' | 'recipe' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility';
273
+ rule: 'theme' | 'structure' | 'layout' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility';
266
274
  severity: 'error' | 'warning';
267
275
  message: string;
268
276
  suggestion?: string;
@@ -272,8 +280,9 @@ interface GuardViolation {
272
280
  }
273
281
  interface GuardContext {
274
282
  pageId?: string;
283
+ theme?: string;
284
+ /** @deprecated Use `theme` instead. */
275
285
  style?: string;
276
- recipe?: string;
277
286
  layout?: string[];
278
287
  density_gap?: string;
279
288
  themeRegistry?: Map<string, {
@@ -297,4 +306,4 @@ declare function migrateV2ToV3(essence: EssenceFile): EssenceV3;
297
306
  */
298
307
  declare function migrateV30ToV31(essence: EssenceV3): EssenceV3;
299
308
 
300
- export { type Accessibility, type ArchetypeRole, type AutoFix, type BlueprintPage, type ColumnLayout, type CvdPreference, type DNAOverrides, type Density, type DensityLevel, type Essence, type EssenceBlueprint, type EssenceDNA, type EssenceFile, type EssenceMeta, type EssenceSection, type EssenceV3, type EssenceV31Section, type EssenceV3Guard, type GeneratorTarget, type Guard, type GuardContext, type GuardMode, type GuardViolation, type Impression, type LayoutItem, type PatternRef, type Platform, type PlatformType, type RouteEntry, type RoutingStrategy, type SectionedEssence, type ShellType, type SpatialTokens, type StructurePage, type Theme, type ThemeMode, type ThemeShape, type ThemeStyle, type ValidationResult, type WcagLevel, computeDensity, computeSpatialTokens, evaluateGuard, flattenPages, isSectioned, isSimple, isV3, migrateV2ToV3, migrateV30ToV31, normalizeEssence, validateEssence };
309
+ export { type Accessibility, type ArchetypeRole, type AutoFix, type BlueprintPage, type ColumnLayout, type CvdPreference, type DNAOverrides, type Density, type DensityLevel, type Essence, type EssenceBlueprint, type EssenceDNA, type EssenceFile, type EssenceMeta, type EssenceSection, type EssenceV3, type EssenceV31Section, type EssenceV3Guard, type GeneratorTarget, type Guard, type GuardContext, type GuardMode, type GuardViolation, type Impression, type LayoutItem, type PatternRef, type Platform, type PlatformType, type RouteEntry, type RoutingStrategy, type SectionedEssence, type ShellGuidance, type ShellType, type SpatialTokenHints, type SpatialTokens, type StructurePage, type Theme, type ThemeMode, type ThemeShape, type ThemeStyle, type ValidationResult, type WcagLevel, computeDensity, computeSpatialTokens, evaluateGuard, flattenPages, isSectioned, isSimple, isV3, migrateV2ToV3, migrateV30ToV31, normalizeEssence, validateEssence };
package/dist/index.js CHANGED
@@ -50,7 +50,8 @@ function getValidator(version) {
50
50
  }
51
51
  function detectVersion(data) {
52
52
  if (typeof data === "object" && data !== null && "version" in data) {
53
- if (data.version === "3.0.0") return "v3";
53
+ const v = data.version;
54
+ if (v === "3.0.0" || v === "3.1.0") return "v3";
54
55
  }
55
56
  return "v2";
56
57
  }
@@ -85,7 +86,7 @@ var MAX_GAP = 10;
85
86
  function clamp(value, min, max) {
86
87
  return Math.max(min, Math.min(max, value));
87
88
  }
88
- function computeDensity(personality, recipeSpatial) {
89
+ function computeDensity(personality, spatialHints) {
89
90
  const lower = personality.map((c) => c.toLowerCase());
90
91
  let level = "comfortable";
91
92
  let gap = 4;
@@ -96,11 +97,11 @@ function computeDensity(personality, recipeSpatial) {
96
97
  break;
97
98
  }
98
99
  }
99
- if (recipeSpatial?.density_bias) {
100
- gap += recipeSpatial.density_bias;
100
+ if (spatialHints?.density_bias) {
101
+ gap += spatialHints.density_bias;
101
102
  }
102
- if (recipeSpatial?.content_gap_shift) {
103
- gap += recipeSpatial.content_gap_shift;
103
+ if (spatialHints?.content_gap_shift) {
104
+ gap += spatialHints.content_gap_shift;
104
105
  }
105
106
  gap = clamp(gap, MIN_GAP, MAX_GAP);
106
107
  if (gap <= 3) level = "compact";
@@ -120,7 +121,11 @@ var BASE_TOKENS = {
120
121
  "--d-surface-p": 1.25,
121
122
  "--d-data-py": 0.625,
122
123
  "--d-control-py": 0.5,
123
- "--d-content-gap": 1
124
+ "--d-content-gap": 1,
125
+ "--d-label-mb": 0.75,
126
+ "--d-label-px": 0.75,
127
+ "--d-section-gap": 1.5,
128
+ "--d-annotation-mt": 0.5
124
129
  };
125
130
  function roundTo3(value) {
126
131
  return Math.round(value * 1e3) / 1e3;
@@ -129,23 +134,41 @@ function toRemString(value) {
129
134
  const rounded = roundTo3(value);
130
135
  return `${rounded}rem`;
131
136
  }
132
- function computeSpatialTokens(density, recipeHints) {
137
+ function computeSpatialTokens(density, spatialHints) {
133
138
  const scale = DENSITY_SCALES[density];
134
- const biasMultiplier = 1 + (recipeHints?.density_bias ?? 0) / 10;
139
+ const biasMultiplier = 1 + (spatialHints?.density_bias ?? 0) / 10;
135
140
  const result = {};
136
141
  for (const [key, base] of Object.entries(BASE_TOKENS)) {
137
142
  const tokenKey = key;
138
- if (tokenKey === "--d-section-py" && recipeHints?.section_padding) {
139
- const pxMatch = recipeHints.section_padding.match(/^(\d+(?:\.\d+)?)px$/);
143
+ if (tokenKey === "--d-label-px") {
144
+ result[tokenKey] = toRemString(base);
145
+ continue;
146
+ }
147
+ if (tokenKey === "--d-section-py" && spatialHints?.section_padding) {
148
+ const pxMatch = spatialHints.section_padding.match(/^(\d+(?:\.\d+)?)px$/);
140
149
  if (pxMatch) {
141
150
  const remValue = parseFloat(pxMatch[1]) / 16;
142
151
  result[tokenKey] = toRemString(remValue * scale * biasMultiplier);
143
152
  continue;
144
153
  }
154
+ const remMatch = spatialHints.section_padding.match(/^(\d+(?:\.\d+)?)rem$/);
155
+ if (remMatch) {
156
+ const remValue = parseFloat(remMatch[1]);
157
+ result[tokenKey] = toRemString(remValue * scale * biasMultiplier);
158
+ continue;
159
+ }
160
+ }
161
+ if (tokenKey === "--d-label-mb" && spatialHints?.label_content_gap) {
162
+ const remMatch = spatialHints.label_content_gap.match(/^(\d+(?:\.\d+)?)rem$/);
163
+ if (remMatch) {
164
+ const remValue = parseFloat(remMatch[1]);
165
+ result[tokenKey] = toRemString(remValue * scale * biasMultiplier);
166
+ continue;
167
+ }
145
168
  }
146
169
  let computed = base * scale * biasMultiplier;
147
- if (tokenKey === "--d-content-gap" && recipeHints?.content_gap_shift) {
148
- computed += recipeHints.content_gap_shift * 0.25;
170
+ if (tokenKey === "--d-content-gap" && spatialHints?.content_gap_shift) {
171
+ computed += spatialHints.content_gap_shift * 0.25;
149
172
  }
150
173
  result[tokenKey] = toRemString(computed);
151
174
  }
@@ -158,10 +181,10 @@ function checkThemeModeCompatibility(essence, context) {
158
181
  let themeId;
159
182
  let mode;
160
183
  if (isV3(essence)) {
161
- themeId = essence.dna.theme?.style ?? null;
184
+ themeId = essence.dna.theme?.id ?? null;
162
185
  mode = essence.dna.theme?.mode ?? null;
163
186
  } else {
164
- themeId = isSimple(essence) ? essence.theme?.style : null;
187
+ themeId = isSimple(essence) ? essence.theme?.id : null;
165
188
  mode = isSimple(essence) ? essence.theme?.mode : null;
166
189
  }
167
190
  if (!themeId || !mode) return null;
@@ -261,19 +284,20 @@ function evaluateGuard(essence, context = {}) {
261
284
  }
262
285
  const violations = [];
263
286
  const isStrict = guard.mode === "strict";
264
- if (context.style) {
265
- let essenceStyle;
287
+ const requestedTheme = context.theme ?? context.style;
288
+ if (requestedTheme) {
289
+ let essenceThemeId;
266
290
  if (isV3(essence)) {
267
- essenceStyle = essence.dna.theme.style;
291
+ essenceThemeId = essence.dna.theme.id;
268
292
  } else {
269
- essenceStyle = isSimple(essence) ? essence.theme.style : null;
293
+ essenceThemeId = isSimple(essence) ? essence.theme.id : null;
270
294
  }
271
295
  const enforceStyle = isV3(essence) ? true : guard.enforce_style !== false;
272
- if (essenceStyle && context.style !== essenceStyle && enforceStyle) {
296
+ if (essenceThemeId && requestedTheme !== essenceThemeId && enforceStyle) {
273
297
  violations.push({
274
- rule: "style",
298
+ rule: "theme",
275
299
  severity: "error",
276
- message: `Style "${context.style}" does not match essence theme "${essenceStyle}". Change the essence theme first.`,
300
+ message: `Theme "${requestedTheme}" does not match essence theme "${essenceThemeId}". Change the essence theme first.`,
277
301
  ...isV3(essence) ? { layer: "dna", autoFixable: false } : {}
278
302
  });
279
303
  }
@@ -317,25 +341,6 @@ function evaluateGuard(essence, context = {}) {
317
341
  }
318
342
  }
319
343
  }
320
- if (context.recipe) {
321
- let essenceRecipe;
322
- let enforceRecipe;
323
- if (isV3(essence)) {
324
- essenceRecipe = essence.dna.theme.recipe;
325
- enforceRecipe = true;
326
- } else {
327
- essenceRecipe = isSimple(essence) ? essence.theme.recipe : null;
328
- enforceRecipe = guard.enforce_recipe !== false;
329
- }
330
- if (essenceRecipe && context.recipe !== essenceRecipe && enforceRecipe) {
331
- violations.push({
332
- rule: "recipe",
333
- severity: "error",
334
- message: `Recipe "${context.recipe}" does not match essence recipe "${essenceRecipe}".`,
335
- ...isV3(essence) ? { layer: "dna", autoFixable: false } : {}
336
- });
337
- }
338
- }
339
344
  if (isStrict && context.density_gap) {
340
345
  let expectedGap;
341
346
  if (isV3(essence)) {
@@ -410,7 +415,7 @@ function getPageDensityOverride(essence, pageId) {
410
415
 
411
416
  // src/normalize.ts
412
417
  function normalizeEssence(input) {
413
- if (input.version === "3.0.0") {
418
+ if (input.version === "3.0.0" || input.version === "3.1.0") {
414
419
  return input;
415
420
  }
416
421
  if (input.theme && input.platform) {
@@ -431,9 +436,8 @@ function normalizeSimple(v1) {
431
436
  version: "2.0.0",
432
437
  archetype: v1.terroir ?? v1.vignette ?? v1.archetype,
433
438
  theme: {
434
- style: vintage?.style ?? "",
439
+ id: vintage?.style ?? "",
435
440
  mode: vintage?.mode ?? "dark",
436
- recipe: vintage?.recipe ?? "",
437
441
  ...vintage?.shape ? { shape: vintage.shape } : {}
438
442
  },
439
443
  // Accept both old 'character' and new 'personality' field names
@@ -471,9 +475,8 @@ function normalizeSectioned(v1) {
471
475
  path: section.path,
472
476
  archetype: section.terroir ?? section.vignette ?? section.archetype,
473
477
  theme: {
474
- style: section.vintage?.style ?? "",
475
- mode: section.vintage?.mode ?? "dark",
476
- recipe: section.vintage?.recipe ?? ""
478
+ id: section.vintage?.style ?? "",
479
+ mode: section.vintage?.mode ?? "dark"
477
480
  },
478
481
  structure: (section.structure ?? []).map(normalizeStructurePage),
479
482
  ...section.tannins ? { features: section.tannins } : {}
@@ -505,7 +508,6 @@ function normalizeGuard(cork) {
505
508
  };
506
509
  return {
507
510
  ...cork.enforce_style !== void 0 ? { enforce_style: cork.enforce_style } : {},
508
- ...cork.enforce_recipe !== void 0 ? { enforce_recipe: cork.enforce_recipe } : {},
509
511
  mode: modeMap[cork.mode ?? "creative"] ?? "creative"
510
512
  };
511
513
  }
@@ -583,9 +585,8 @@ function buildDNA(essence) {
583
585
  const radiusBase = inferRadiusBase(shape);
584
586
  return {
585
587
  theme: {
586
- style: essence.theme.style,
588
+ id: essence.theme.id,
587
589
  mode: essence.theme.mode,
588
- recipe: essence.theme.recipe,
589
590
  ...essence.theme.shape ? { shape: essence.theme.shape } : {}
590
591
  },
591
592
  spacing: {
@@ -678,7 +679,7 @@ function migrateV30ToV31(essence) {
678
679
  role: "primary",
679
680
  shell: essence.blueprint.shell ?? "top-nav-main",
680
681
  features: essence.blueprint.features,
681
- description: "",
682
+ description: `${essence.meta.archetype} primary section`,
682
683
  pages: essence.blueprint.pages ?? []
683
684
  };
684
685
  return {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/validate.ts","../src/density.ts","../src/guard.ts","../src/normalize.ts","../src/migrate.ts"],"sourcesContent":["/**\n * Essence v2 schema types — normalized terminology.\n *\n * Terminology mapping (v1 wine terms → v2 normalized):\n * terroir → archetype, vintage → theme, tannins → features,\n * carafe → shell, cork → guard, blend → layout, clarity → density,\n * vessel → platform, character → personality,\n * decantation process → essence pipeline\n */\n\n// --- Theme ---\n\nexport type ThemeStyle =\n | 'auradecantism'\n | 'clean'\n | 'glassmorphism'\n | 'retro'\n | 'bioluminescent'\n | 'launchpad'\n | 'dopamine'\n | 'editorial'\n | 'liquid-glass'\n | 'prismatic';\n\nexport type ThemeMode = 'light' | 'dark' | 'auto';\nexport type ThemeShape = 'sharp' | 'rounded' | 'pill';\n\nexport interface Theme {\n style: ThemeStyle | string;\n mode: ThemeMode;\n recipe: string;\n shape?: ThemeShape;\n}\n\n// --- Platform ---\n\nexport type PlatformType = 'spa' | 'ssr' | 'static';\nexport type RoutingStrategy = 'hash' | 'history';\n\nexport interface Platform {\n type: PlatformType;\n routing: RoutingStrategy;\n}\n\n// --- Structure ---\n\nexport type ShellType =\n | 'sidebar-main'\n | 'top-nav-main'\n | 'full-bleed'\n | 'dashboard'\n | 'stacked'\n | string;\n\nexport type LayoutItem = string | PatternRef | ColumnLayout;\n\nexport interface PatternRef {\n pattern: string;\n preset?: string;\n as?: string;\n}\n\nexport interface ColumnLayout {\n cols: string[];\n at?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n span?: Record<string, number>;\n // AUTO: Multi-breakpoint grid — array of { at, cols } entries for cascading breakpoints\n breakpoints?: { at: string; cols: number }[];\n // AUTO: \"container\" uses container queries instead of viewport breakpoints\n responsive?: 'viewport' | 'container';\n}\n\nexport interface StructurePage {\n id: string;\n shell: ShellType;\n layout: LayoutItem[];\n surface?: string;\n}\n\n// --- Density ---\n\nexport type DensityLevel = 'compact' | 'comfortable' | 'spacious';\n\nexport interface Density {\n level: DensityLevel;\n content_gap: string;\n}\n\nexport interface SpatialTokens {\n '--d-section-py': string;\n '--d-interactive-py': string;\n '--d-interactive-px': string;\n '--d-surface-p': string;\n '--d-data-py': string;\n '--d-control-py': string;\n '--d-content-gap': string;\n}\n\n// --- Guard ---\n\nexport type GuardMode = 'creative' | 'guided' | 'strict';\n\nexport interface Guard {\n enforce_style?: boolean;\n enforce_recipe?: boolean;\n mode: GuardMode;\n}\n\n// --- Impression ---\n\nexport interface Impression {\n vibe: string[];\n references: string[];\n density_intent: DensityLevel | string;\n layout_intent: ShellType | string;\n novel_elements: string[];\n}\n\n// --- Generator Target ---\n\nexport type GeneratorTarget = 'decantr' | 'react' | 'vue' | 'svelte' | string;\n\n// --- Accessibility ---\n\nexport type WcagLevel = 'none' | 'A' | 'AA' | 'AAA';\n\nexport type CvdPreference =\n | 'none'\n | 'auto'\n | 'deuteranopia'\n | 'protanopia'\n | 'tritanopia'\n | 'achromatopsia';\n\nexport interface Accessibility {\n wcag_level?: WcagLevel;\n cvd_preference?: CvdPreference;\n}\n\n// --- Essence (simple) ---\n\nexport interface Essence {\n $schema?: string;\n version: string;\n archetype: string;\n theme: Theme;\n personality: string[];\n platform: Platform;\n structure: StructurePage[];\n features: string[];\n density: Density;\n guard: Guard;\n target: GeneratorTarget;\n accessibility?: Accessibility;\n _impression?: Impression;\n}\n\n// --- Essence (sectioned) ---\n\nexport interface EssenceSection {\n id: string;\n path: string;\n archetype: string;\n theme: Theme;\n structure: StructurePage[];\n features?: string[];\n}\n\nexport interface SectionedEssence {\n $schema?: string;\n version: string;\n platform: Platform;\n personality: string[];\n sections: EssenceSection[];\n shared_features?: string[];\n density: Density;\n guard: Guard;\n target: GeneratorTarget;\n accessibility?: Accessibility;\n _impression?: Impression;\n}\n\n// --- Essence v3: DNA/Blueprint/Meta split ---\n\nexport interface EssenceDNA {\n theme: Theme;\n spacing: {\n base_unit: number;\n scale: string;\n density: DensityLevel;\n content_gap: string;\n };\n typography: {\n scale: string;\n heading_weight: number;\n body_weight: number;\n };\n color: {\n palette: string;\n accent_count: number;\n cvd_preference: CvdPreference | string;\n };\n radius: {\n philosophy: ThemeShape | string;\n base: number;\n };\n elevation: {\n system: string;\n max_levels: number;\n };\n motion: {\n preference: string;\n duration_scale: number;\n reduce_motion: boolean;\n timing?: string;\n durations?: Record<string, string>;\n };\n accessibility: {\n wcag_level: WcagLevel;\n focus_visible: boolean;\n skip_nav: boolean;\n };\n personality: string[];\n constraints?: {\n mode?: string;\n typography?: string;\n borders?: string;\n corners?: string;\n shadows?: string;\n effects?: Record<string, string>;\n };\n}\n\n/** Only density and mode may be overridden per-page. DNA axioms like wcag_level and theme.style are never overrideable. */\nexport interface DNAOverrides {\n density?: DensityLevel;\n mode?: ThemeMode;\n}\n\nexport interface BlueprintPage {\n id: string;\n route?: string;\n shell_override?: ShellType | null;\n layout: LayoutItem[];\n patterns?: PatternRef[];\n dna_overrides?: DNAOverrides;\n surface?: string;\n}\n\nexport type ArchetypeRole = 'primary' | 'gateway' | 'public' | 'auxiliary';\n\nexport interface EssenceV31Section {\n id: string;\n role: ArchetypeRole;\n shell: ShellType | string;\n features: string[];\n description: string;\n pages: BlueprintPage[];\n dna_overrides?: DNAOverrides;\n}\n\nexport interface RouteEntry {\n section: string;\n page: string;\n}\n\nexport interface EssenceBlueprint {\n shell?: ShellType | string;\n sections?: EssenceV31Section[];\n pages?: BlueprintPage[];\n features: string[];\n routes?: Record<string, RouteEntry>;\n icon_style?: string;\n avatar_style?: string;\n}\n\nexport interface EssenceV3Guard {\n mode: GuardMode;\n dna_enforcement: 'error' | 'warn' | 'off';\n blueprint_enforcement: 'warn' | 'off';\n}\n\nexport interface EssenceMeta {\n archetype: string;\n target: GeneratorTarget;\n platform: Platform;\n guard: EssenceV3Guard;\n seo?: {\n schema_org?: string[];\n meta_priorities?: string[];\n };\n navigation?: {\n hotkeys?: Array<{ key: string; route?: string; action?: string; label: string }>;\n command_palette?: boolean;\n };\n}\n\nexport interface EssenceV3 {\n $schema?: string;\n version: '3.0.0' | '3.1.0';\n dna: EssenceDNA;\n blueprint: EssenceBlueprint;\n meta: EssenceMeta;\n _impression?: Impression;\n}\n\n// --- Discriminated union ---\n\nexport type EssenceFile = Essence | SectionedEssence | EssenceV3;\n\nexport function isV3(essence: EssenceFile): essence is EssenceV3 {\n return (essence.version === '3.0.0' || essence.version === '3.1.0') && 'dna' in essence && 'blueprint' in essence;\n}\n\n/** Flatten sections into a flat page list (for guards and backward compat). */\nexport function flattenPages(blueprint: EssenceBlueprint): BlueprintPage[] {\n if (blueprint.sections && blueprint.sections.length > 0) {\n return blueprint.sections.flatMap(s =>\n s.pages.map(p => ({\n ...p,\n shell_override: p.shell_override ?? (s.shell !== blueprint.shell ? (s.shell as ShellType) : undefined),\n }))\n );\n }\n return blueprint.pages ?? [];\n}\n\nexport function isSectioned(essence: EssenceFile): essence is SectionedEssence {\n if (isV3(essence)) return false;\n return 'sections' in essence && Array.isArray((essence as SectionedEssence).sections);\n}\n\nexport function isSimple(essence: EssenceFile): essence is Essence {\n if (isV3(essence)) return false;\n return 'archetype' in essence && !('sections' in essence);\n}\n","import Ajv from 'ajv';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst v2SchemaPath = join(__dirname, '..', 'schema', 'essence.v2.json');\nconst v3SchemaPath = join(__dirname, '..', 'schema', 'essence.v3.json');\n\nlet cachedAjv: Ajv | null = null;\nconst validatorCache = new Map<string, ReturnType<Ajv['compile']>>();\n\nfunction getAjv(): Ajv {\n if (!cachedAjv) {\n cachedAjv = new Ajv({ allErrors: true, strict: false, validateSchema: false });\n }\n return cachedAjv;\n}\n\nfunction getValidator(version: 'v2' | 'v3'): ReturnType<Ajv['compile']> | null {\n if (validatorCache.has(version)) return validatorCache.get(version)!;\n\n const schemaPath = version === 'v3' ? v3SchemaPath : v2SchemaPath;\n if (!existsSync(schemaPath)) return null;\n\n const schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));\n const ajv = getAjv();\n const validate = ajv.compile(schema);\n validatorCache.set(version, validate);\n return validate;\n}\n\nfunction detectVersion(data: unknown): 'v2' | 'v3' {\n if (typeof data === 'object' && data !== null && 'version' in data) {\n if ((data as Record<string, unknown>).version === '3.0.0') return 'v3';\n }\n return 'v2';\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateEssence(data: unknown): ValidationResult {\n const version = detectVersion(data);\n const validate = getValidator(version);\n\n if (!validate) {\n return { valid: false, errors: [`No schema available for ${version} documents`] };\n }\n\n const valid = validate(data);\n\n if (valid) {\n return { valid: true, errors: [] };\n }\n\n const errors = (validate.errors ?? []).map((err) => {\n const path = err.instancePath || '/';\n const msg = err.message ?? 'unknown error';\n return `${path}: ${msg}`;\n });\n\n return { valid: false, errors };\n}\n","import type { Density, DensityLevel, SpatialTokens } from './types.js';\n\ninterface RecipeSpatialHints {\n density_bias?: number;\n content_gap_shift?: number;\n}\n\ninterface DensityRule {\n traits: string[];\n level: DensityLevel;\n gap: number;\n}\n\nconst RULES: DensityRule[] = [\n { traits: ['tactical', 'dense', 'data-dense', 'utilitarian'], level: 'compact', gap: 3 },\n { traits: ['luxurious', 'premium', 'editorial'], level: 'spacious', gap: 8 },\n { traits: ['playful', 'bouncy', 'expressive'], level: 'comfortable', gap: 5 },\n { traits: ['minimal', 'clean', 'airy'], level: 'spacious', gap: 6 },\n { traits: ['professional', 'modern', 'balanced'], level: 'comfortable', gap: 4 },\n];\n\nconst MIN_GAP = 2;\nconst MAX_GAP = 10;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function computeDensity(\n personality: string[],\n recipeSpatial?: RecipeSpatialHints,\n): Density {\n const lower = personality.map(c => c.toLowerCase());\n\n let level: DensityLevel = 'comfortable';\n let gap = 4;\n\n for (const rule of RULES) {\n if (rule.traits.some(t => lower.includes(t))) {\n level = rule.level;\n gap = rule.gap;\n break;\n }\n }\n\n if (recipeSpatial?.density_bias) {\n gap += recipeSpatial.density_bias;\n }\n if (recipeSpatial?.content_gap_shift) {\n gap += recipeSpatial.content_gap_shift;\n }\n\n gap = clamp(gap, MIN_GAP, MAX_GAP);\n\n if (gap <= 3) level = 'compact';\n else if (gap >= 6) level = 'spacious';\n else level = 'comfortable';\n\n return { level, content_gap: String(gap) };\n}\n\n// --- Spatial Tokens ---\n\ninterface SpatialRecipeHints {\n section_padding?: string | null;\n density_bias?: number;\n content_gap_shift?: number;\n}\n\nconst DENSITY_SCALES: Record<DensityLevel, number> = {\n compact: 0.65,\n comfortable: 1.0,\n spacious: 1.4,\n};\n\nconst BASE_TOKENS = {\n '--d-section-py': 5,\n '--d-interactive-py': 0.5,\n '--d-interactive-px': 1,\n '--d-surface-p': 1.25,\n '--d-data-py': 0.625,\n '--d-control-py': 0.5,\n '--d-content-gap': 1,\n} as const;\n\nfunction roundTo3(value: number): number {\n return Math.round(value * 1000) / 1000;\n}\n\nfunction toRemString(value: number): string {\n const rounded = roundTo3(value);\n return `${rounded}rem`;\n}\n\nexport function computeSpatialTokens(\n density: DensityLevel,\n recipeHints?: SpatialRecipeHints,\n): SpatialTokens {\n const scale = DENSITY_SCALES[density];\n const biasMultiplier = 1 + (recipeHints?.density_bias ?? 0) / 10;\n\n const result = {} as SpatialTokens;\n\n for (const [key, base] of Object.entries(BASE_TOKENS)) {\n const tokenKey = key as keyof SpatialTokens;\n\n if (tokenKey === '--d-section-py' && recipeHints?.section_padding) {\n const pxMatch = recipeHints.section_padding.match(/^(\\d+(?:\\.\\d+)?)px$/);\n if (pxMatch) {\n const remValue = parseFloat(pxMatch[1]) / 16;\n result[tokenKey] = toRemString(remValue * scale * biasMultiplier);\n continue;\n }\n }\n\n let computed = base * scale * biasMultiplier;\n\n if (tokenKey === '--d-content-gap' && recipeHints?.content_gap_shift) {\n computed += recipeHints.content_gap_shift * 0.25;\n }\n\n result[tokenKey] = toRemString(computed);\n }\n\n return result;\n}\n","import type { EssenceFile, EssenceV3, EssenceV3Guard, StructurePage, LayoutItem, DensityLevel } from './types.js';\nimport { isSimple, isSectioned, isV3, flattenPages } from './types.js';\n\nexport interface AutoFix {\n type: 'add_page' | 'update_layout' | 'update_blueprint';\n patch: Record<string, unknown>;\n}\n\nexport interface GuardViolation {\n rule: 'style' | 'structure' | 'layout' | 'recipe' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility';\n severity: 'error' | 'warning';\n message: string;\n suggestion?: string;\n layer?: 'dna' | 'blueprint';\n autoFixable?: boolean;\n autoFix?: AutoFix;\n}\n\nexport interface GuardContext {\n pageId?: string;\n style?: string;\n recipe?: string;\n layout?: string[];\n density_gap?: string;\n themeRegistry?: Map<string, { modes: string[] }>;\n patternRegistry?: Map<string, unknown>;\n a11y_issues?: string[];\n}\n\n/**\n * Check if the theme supports the specified mode.\n */\nfunction checkThemeModeCompatibility(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation | null {\n if (!context.themeRegistry) return null;\n\n let themeId: string | null;\n let mode: string | null;\n if (isV3(essence)) {\n themeId = essence.dna.theme?.style ?? null;\n mode = essence.dna.theme?.mode ?? null;\n } else {\n themeId = isSimple(essence) ? essence.theme?.style : null;\n mode = isSimple(essence) ? essence.theme?.mode : null;\n }\n\n if (!themeId || !mode) return null;\n\n const theme = context.themeRegistry.get(themeId);\n if (!theme) {\n // Theme not found - separate validation\n return null;\n }\n\n if (!theme.modes.includes(mode) && mode !== 'auto') {\n const supportedModes = theme.modes.join(', ');\n const suggestion = theme.modes.length > 0\n ? `Use mode: \"${theme.modes[0]}\" instead, or choose a theme that supports ${mode} mode.`\n : undefined;\n\n return {\n rule: 'theme-mode',\n severity: 'error',\n message: `Theme \"${themeId}\" does not support \"${mode}\" mode. Supported modes: ${supportedModes}.`,\n suggestion,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n };\n }\n\n return null;\n}\n\n/**\n * Collect all pattern IDs from a layout item, recursively handling nested structures.\n */\nfunction collectPatternIds(item: LayoutItem, ids: Set<string>): void {\n if (typeof item === 'string') {\n ids.add(item);\n return;\n }\n if (typeof item === 'object' && item !== null) {\n if ('pattern' in item && typeof item.pattern === 'string') {\n ids.add(item.pattern);\n }\n if ('cols' in item && Array.isArray(item.cols)) {\n for (const col of item.cols) {\n // cols contains strings (pattern IDs)\n if (typeof col === 'string') {\n ids.add(col);\n }\n }\n }\n }\n}\n\n/**\n * Find similar pattern IDs in the registry for suggestion.\n */\nfunction findSimilarPatterns(target: string, registry: Map<string, unknown>): string[] {\n const similar: string[] = [];\n const targetLower = target.toLowerCase();\n\n for (const id of registry.keys()) {\n const idLower = id.toLowerCase();\n // Simple similarity: contains target or target contains id\n if (idLower.includes(targetLower) || targetLower.includes(idLower)) {\n similar.push(id);\n }\n }\n\n return similar.slice(0, 3); // Top 3 suggestions\n}\n\n/**\n * Check if all referenced patterns exist in the registry.\n */\nfunction checkPatternExistence(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation[] {\n if (!context.patternRegistry) return [];\n\n const violations: GuardViolation[] = [];\n const referencedPatterns = new Set<string>();\n\n // Collect all pattern references from structure\n const pages = getAllPages(essence);\n for (const page of pages) {\n for (const item of page.layout || []) {\n collectPatternIds(item, referencedPatterns);\n }\n }\n\n // Check each pattern exists\n for (const patternId of referencedPatterns) {\n if (!context.patternRegistry.has(patternId)) {\n // Find similar patterns for suggestion\n const similar = findSimilarPatterns(patternId, context.patternRegistry);\n const suggestion = similar.length > 0\n ? `Similar patterns: ${similar.join(', ')}`\n : `Run \"decantr search ${patternId}\" to find alternatives.`;\n\n violations.push({\n rule: 'pattern-exists',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Pattern \"${patternId}\" is referenced but does not exist in the registry.`,\n suggestion,\n ...(isV3(essence) ? { layer: 'blueprint' as const, autoFixable: false } : {}),\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Check accessibility compliance based on declared WCAG level.\n */\nfunction checkAccessibility(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation | null {\n const accessibility = isV3(essence) ? essence.dna.accessibility : ('accessibility' in essence ? essence.accessibility : undefined);\n\n if (!accessibility?.wcag_level || accessibility.wcag_level === 'none') {\n return null;\n }\n\n if (context.a11y_issues && context.a11y_issues.length > 0) {\n const issueList = context.a11y_issues.slice(0, 3).join(', ');\n const moreCount = context.a11y_issues.length > 3 ? ` (+${context.a11y_issues.length - 3} more)` : '';\n\n return {\n rule: 'accessibility',\n severity: 'error',\n message: `WCAG ${accessibility.wcag_level} compliance required. Issues found: ${issueList}${moreCount}`,\n suggestion: 'Fix accessibility issues before proceeding. Run an accessibility audit for details.',\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n };\n }\n\n return null;\n}\n\nexport function evaluateGuard(essence: EssenceFile, context: GuardContext = {}): GuardViolation[] {\n const guard = isV3(essence) ? essence.meta.guard : essence.guard;\n\n if (guard.mode === 'creative') {\n return [];\n }\n\n const violations: GuardViolation[] = [];\n const isStrict = guard.mode === 'strict';\n\n // Rule 1: Style guard\n if (context.style) {\n let essenceStyle: string | null;\n if (isV3(essence)) {\n essenceStyle = essence.dna.theme.style;\n } else {\n essenceStyle = isSimple(essence) ? essence.theme.style : null;\n }\n const enforceStyle = isV3(essence) ? true : (guard as import('./types.js').Guard).enforce_style !== false;\n if (essenceStyle && context.style !== essenceStyle && enforceStyle) {\n violations.push({\n rule: 'style',\n severity: 'error',\n message: `Style \"${context.style}\" does not match essence theme \"${essenceStyle}\". Change the essence theme first.`,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n });\n }\n }\n\n // Rule 2: Structure guard (enforced in both guided and strict)\n if (context.pageId) {\n const pages = getAllPages(essence);\n const pageExists = pages.some(p => p.id === context.pageId);\n if (!pageExists) {\n violations.push({\n rule: 'structure',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Page \"${context.pageId}\" does not exist in essence structure. Add it to the essence first.`,\n ...(isV3(essence) ? {\n layer: 'blueprint' as const,\n autoFixable: true,\n autoFix: { type: 'add_page' as const, patch: { id: context.pageId } },\n } : {}),\n });\n }\n }\n\n // Rule 3: Layout guard (strict only)\n if (isStrict && context.pageId && context.layout) {\n const pages = getAllPages(essence);\n const page = pages.find(p => p.id === context.pageId);\n if (page) {\n const essenceLayout = page.layout.map(item =>\n typeof item === 'string' ? item : 'pattern' in item ? item.pattern : 'cols'\n );\n const proposedLayout = context.layout;\n const matches = essenceLayout.length === proposedLayout.length &&\n essenceLayout.every((item, i) => item === proposedLayout[i]);\n if (!matches) {\n violations.push({\n rule: 'layout',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Layout for page \"${context.pageId}\" deviates from essence. Expected: [${essenceLayout.join(', ')}].`,\n ...(isV3(essence) ? {\n layer: 'blueprint' as const,\n autoFixable: true,\n autoFix: { type: 'update_layout' as const, patch: { page: context.pageId, layout: context.layout } },\n } : {}),\n });\n }\n }\n }\n\n // Rule 4: Recipe guard\n if (context.recipe) {\n let essenceRecipe: string | null;\n let enforceRecipe: boolean;\n if (isV3(essence)) {\n essenceRecipe = essence.dna.theme.recipe;\n enforceRecipe = true;\n } else {\n essenceRecipe = isSimple(essence) ? essence.theme.recipe : null;\n enforceRecipe = (guard as import('./types.js').Guard).enforce_recipe !== false;\n }\n if (essenceRecipe && context.recipe !== essenceRecipe && enforceRecipe) {\n violations.push({\n rule: 'recipe',\n severity: 'error',\n message: `Recipe \"${context.recipe}\" does not match essence recipe \"${essenceRecipe}\".`,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n });\n }\n }\n\n // Rule 5: Density guard (strict only)\n if (isStrict && context.density_gap) {\n let expectedGap: string;\n if (isV3(essence)) {\n // Check per-page dna_overrides for density if a pageId is provided\n const overriddenDensity = getPageDensityOverride(essence, context.pageId);\n expectedGap = overriddenDensity ?? essence.dna.spacing.content_gap;\n } else {\n expectedGap = essence.density.content_gap;\n }\n if (context.density_gap !== expectedGap) {\n violations.push({\n rule: 'density',\n severity: 'warning',\n message: `Content gap \"${context.density_gap}\" does not match essence density \"${expectedGap}\".`,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n });\n }\n }\n\n // Rule 6: Theme/mode compatibility (always checked when registry available)\n const themeModeViolation = checkThemeModeCompatibility(essence, context);\n if (themeModeViolation) {\n violations.push(themeModeViolation);\n }\n\n // Rule 7: Pattern existence (always checked when registry available)\n const patternViolations = checkPatternExistence(essence, context);\n violations.push(...patternViolations);\n\n // Rule 8: Accessibility (when wcag_level is set, guided and strict modes)\n const accessibilityViolation = checkAccessibility(essence, context);\n if (accessibilityViolation) {\n violations.push(accessibilityViolation);\n }\n\n // Apply v3 enforcement level filtering\n if (isV3(essence)) {\n const v3Guard = guard as EssenceV3Guard;\n\n // DNA enforcement\n if (v3Guard.dna_enforcement === 'off') {\n // Remove all DNA-layer violations\n return violations.filter(v => v.layer !== 'dna');\n }\n if (v3Guard.dna_enforcement === 'warn') {\n // Downgrade DNA-layer violations to warning severity\n for (const v of violations) {\n if (v.layer === 'dna') {\n v.severity = 'warning';\n }\n }\n }\n\n // Blueprint enforcement\n if (v3Guard.blueprint_enforcement === 'off') {\n // Remove all blueprint-layer violations\n return violations.filter(v => v.layer !== 'blueprint');\n }\n }\n\n return violations;\n}\n\nfunction getAllPages(essence: EssenceFile): StructurePage[] {\n if (isV3(essence)) {\n // Map v3 BlueprintPages to StructurePage shape for guard evaluation\n const pages = flattenPages(essence.blueprint);\n return pages.map(page => ({\n id: page.id,\n shell: page.shell_override ?? essence.blueprint.shell ?? '',\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n }));\n }\n if (isSimple(essence)) return essence.structure;\n if (isSectioned(essence)) return essence.sections.flatMap(s => s.structure);\n throw new Error('Unknown EssenceFile type');\n}\n\n/** Get per-page density override from v3 blueprint, if set. */\nfunction getPageDensityOverride(essence: EssenceV3, pageId?: string): string | undefined {\n if (!pageId) return undefined;\n const pages = flattenPages(essence.blueprint);\n const page = pages.find(p => p.id === pageId);\n if (!page?.dna_overrides?.density) return undefined;\n // Map density level to a content_gap value\n const densityGapMap: Record<DensityLevel, string> = {\n compact: '2',\n comfortable: '4',\n spacious: '6',\n };\n return densityGapMap[page.dna_overrides.density] ?? undefined;\n}\n","import type { Essence, SectionedEssence, EssenceFile, EssenceV3, StructurePage, GuardMode } from './types.js';\n\nexport function normalizeEssence(input: Record<string, unknown>): EssenceFile {\n // v3: version-based detection only (no structural fallback to avoid false positives)\n if (input.version === '3.0.0') {\n return input as unknown as EssenceV3;\n }\n\n // Detect v2: has 'theme' and 'platform' (normalized terms)\n if (input.theme && input.platform) {\n return input as unknown as EssenceFile;\n }\n\n if (input.sections) {\n return normalizeSectioned(input);\n }\n\n return normalizeSimple(input);\n}\n\nfunction normalizeSimple(v1: Record<string, unknown>): Essence {\n // v1 field names (wine terms) → v2 normalized names:\n // vintage → theme, vessel → platform, clarity → density,\n // cork → guard, terroir/vignette → archetype, tannins → features,\n // carafe → shell, blend → layout, character → personality\n const vintage = v1.vintage as Record<string, string> | undefined;\n const vessel = v1.vessel as Record<string, string> | undefined;\n const clarity = v1.clarity as Record<string, string> | undefined;\n const cork = v1.cork as Record<string, unknown> | undefined;\n const structure = v1.structure as Array<Record<string, unknown>> | undefined;\n\n return {\n version: '2.0.0',\n archetype: (v1.terroir ?? v1.vignette ?? v1.archetype) as string,\n theme: {\n style: vintage?.style ?? '',\n mode: (vintage?.mode ?? 'dark') as 'light' | 'dark' | 'auto',\n recipe: vintage?.recipe ?? '',\n ...(vintage?.shape ? { shape: vintage.shape as 'sharp' | 'rounded' | 'pill' } : {}),\n },\n // Accept both old 'character' and new 'personality' field names\n personality: (v1.character ?? v1.personality) as string[],\n platform: {\n type: (vessel?.type ?? 'spa') as 'spa' | 'ssr' | 'static',\n routing: (vessel?.routing ?? 'hash') as 'hash' | 'history',\n },\n structure: (structure ?? []).map(normalizeStructurePage),\n features: (v1.tannins ?? v1.features ?? []) as string[],\n density: {\n level: (clarity?.density ?? 'comfortable') as 'compact' | 'comfortable' | 'spacious',\n content_gap: stripGapPrefix(clarity?.content_gap ?? '4'),\n },\n guard: normalizeGuard(cork),\n target: (v1.target as string) ?? 'decantr',\n ...(v1._impression ? { _impression: v1._impression as Essence['_impression'] } : {}),\n };\n}\n\nfunction normalizeSectioned(v1: Record<string, unknown>): SectionedEssence {\n // v1 field names (wine terms) → v2 normalized names:\n // vessel → platform, clarity → density, cork → guard,\n // terroir/vignette → archetype, tannins → features,\n // shared_tannins → shared_features, character → personality\n const vessel = v1.vessel as Record<string, string> | undefined;\n const clarity = v1.clarity as Record<string, string> | undefined;\n const cork = v1.cork as Record<string, unknown> | undefined;\n const sections = v1.sections as Array<Record<string, unknown>>;\n\n return {\n version: '2.0.0',\n platform: {\n type: (vessel?.type ?? 'spa') as 'spa' | 'ssr' | 'static',\n routing: (vessel?.routing ?? 'hash') as 'hash' | 'history',\n },\n // Accept both old 'character' and new 'personality' field names\n personality: (v1.character ?? v1.personality) as string[],\n sections: sections.map(section => ({\n id: section.id as string,\n path: section.path as string,\n archetype: (section.terroir ?? section.vignette ?? section.archetype) as string,\n theme: {\n style: (section.vintage as Record<string, string>)?.style ?? '',\n mode: ((section.vintage as Record<string, string>)?.mode ?? 'dark') as 'light' | 'dark' | 'auto',\n recipe: (section.vintage as Record<string, string>)?.recipe ?? '',\n },\n structure: ((section.structure as Array<Record<string, unknown>>) ?? []).map(normalizeStructurePage),\n ...(section.tannins ? { features: section.tannins as string[] } : {}),\n })),\n ...(v1.shared_tannins ? { shared_features: v1.shared_tannins as string[] } : {}),\n density: {\n level: (clarity?.density ?? 'comfortable') as 'compact' | 'comfortable' | 'spacious',\n content_gap: stripGapPrefix(clarity?.content_gap ?? '4'),\n },\n guard: normalizeGuard(cork),\n target: (v1.target as string) ?? 'decantr',\n };\n}\n\nfunction normalizeStructurePage(page: Record<string, unknown>): StructurePage {\n // Accept v1 wine terms (carafe → shell, blend → layout) for backward compatibility\n return {\n id: page.id as string,\n shell: (page.carafe ?? page.shell) as string,\n layout: (page.blend ?? page.layout) as StructurePage['layout'],\n ...(page.surface ? { surface: page.surface as string } : {}),\n };\n}\n\n// Accept v1 'cork' object and normalize to v2 'guard'\nfunction normalizeGuard(cork: Record<string, unknown> | undefined): Essence['guard'] {\n if (!cork) return { mode: 'creative' };\n\n const modeMap: Record<string, GuardMode> = {\n creative: 'creative',\n maintenance: 'strict',\n strict: 'strict',\n guided: 'guided',\n };\n\n return {\n ...(cork.enforce_style !== undefined ? { enforce_style: cork.enforce_style as boolean } : {}),\n ...(cork.enforce_recipe !== undefined ? { enforce_recipe: cork.enforce_recipe as boolean } : {}),\n mode: modeMap[(cork.mode as string) ?? 'creative'] ?? 'creative',\n };\n}\n\nfunction stripGapPrefix(gap: string): string {\n const match = gap.match(/^_gap(\\d+)$/);\n return match ? match[1] : gap;\n}\n","import type {\n Essence,\n SectionedEssence,\n EssenceV3,\n EssenceFile,\n EssenceDNA,\n EssenceBlueprint,\n EssenceMeta,\n EssenceV31Section,\n ThemeShape,\n DensityLevel,\n GuardMode,\n} from './types.js';\nimport { isSimple, isSectioned, isV3 } from './types.js';\n\n/**\n * Migrate a v2 EssenceFile to v3 format (DNA/Blueprint/Meta split).\n * If already v3, returns unchanged. SectionedEssence uses first section's theme.\n */\nexport function migrateV2ToV3(essence: EssenceFile): EssenceV3 {\n if (isV3(essence)) return essence;\n\n if (isSectioned(essence)) {\n return migrateSectionedToV3(essence);\n }\n\n if (isSimple(essence)) {\n return migrateSimpleToV3(essence);\n }\n\n throw new Error('Unknown EssenceFile type — cannot migrate');\n}\n\nfunction migrateSimpleToV3(essence: Essence): EssenceV3 {\n const dna = buildDNA(essence);\n const blueprint = buildBlueprintFromSimple(essence);\n const meta = buildMeta(essence);\n\n return {\n version: '3.0.0',\n dna,\n blueprint,\n meta,\n ...(essence._impression ? { _impression: essence._impression } : {}),\n };\n}\n\nfunction migrateSectionedToV3(essence: SectionedEssence): EssenceV3 {\n // Use first section's theme as the DNA theme (sectioned essences have per-section themes)\n const firstSection = essence.sections[0];\n const syntheticSimple: Partial<Essence> = {\n theme: firstSection.theme,\n density: essence.density,\n guard: essence.guard,\n accessibility: essence.accessibility,\n };\n\n const dna = buildDNA(syntheticSimple as Essence);\n // Override personality from the sectioned root\n dna.personality = essence.personality;\n\n // Flatten all sections' pages into the blueprint\n const pages = essence.sections.flatMap(section =>\n section.structure.map(page => ({\n id: page.id,\n shell_override: page.shell as string | null,\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n }))\n );\n\n const allFeatures = [\n ...(essence.shared_features ?? []),\n ...essence.sections.flatMap(s => s.features ?? []),\n ];\n\n const blueprint: EssenceBlueprint = {\n shell: firstSection.structure[0]?.shell ?? 'top-nav-main',\n pages,\n features: [...new Set(allFeatures)],\n };\n\n const meta: EssenceMeta = {\n archetype: firstSection.archetype,\n target: essence.target,\n platform: essence.platform,\n guard: migrateGuard(essence.guard.mode),\n };\n\n return {\n version: '3.0.0',\n dna,\n blueprint,\n meta,\n ...(essence._impression ? { _impression: essence._impression } : {}),\n };\n}\n\nfunction buildDNA(essence: Essence): EssenceDNA {\n const shape = essence.theme.shape ?? 'rounded';\n const radiusBase = inferRadiusBase(shape);\n\n return {\n theme: {\n style: essence.theme.style,\n mode: essence.theme.mode,\n recipe: essence.theme.recipe,\n ...(essence.theme.shape ? { shape: essence.theme.shape } : {}),\n },\n spacing: {\n base_unit: 4,\n scale: 'linear',\n density: (essence.density?.level ?? 'comfortable') as DensityLevel,\n content_gap: essence.density?.content_gap ?? '4',\n },\n typography: {\n scale: 'modular',\n heading_weight: 600,\n body_weight: 400,\n },\n color: {\n palette: 'semantic',\n accent_count: 1,\n cvd_preference: essence.accessibility?.cvd_preference ?? 'auto',\n },\n radius: {\n philosophy: shape,\n base: radiusBase,\n },\n elevation: {\n system: 'layered',\n max_levels: 3,\n },\n motion: {\n preference: 'subtle',\n duration_scale: 1.0,\n reduce_motion: true,\n },\n accessibility: {\n wcag_level: essence.accessibility?.wcag_level ?? 'AA',\n focus_visible: true,\n skip_nav: true,\n },\n personality: essence.personality ?? ['professional'],\n };\n}\n\nfunction buildBlueprintFromSimple(essence: Essence): EssenceBlueprint {\n const defaultShell = essence.structure[0]?.shell ?? 'top-nav-main';\n\n return {\n shell: defaultShell,\n pages: essence.structure.map(page => ({\n id: page.id,\n ...(page.shell !== defaultShell ? { shell_override: page.shell } : {}),\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n })),\n features: essence.features ?? [],\n };\n}\n\nfunction buildMeta(essence: Essence): EssenceMeta {\n return {\n archetype: essence.archetype,\n target: essence.target,\n platform: essence.platform,\n guard: migrateGuard(essence.guard.mode),\n };\n}\n\nfunction migrateGuard(mode: GuardMode): EssenceMeta['guard'] {\n switch (mode) {\n case 'strict':\n return { mode: 'strict', dna_enforcement: 'error', blueprint_enforcement: 'warn' };\n case 'guided':\n return { mode: 'guided', dna_enforcement: 'error', blueprint_enforcement: 'off' };\n case 'creative':\n default:\n return { mode: 'creative', dna_enforcement: 'off', blueprint_enforcement: 'off' };\n }\n}\n\nfunction inferRadiusBase(shape: ThemeShape | string): number {\n switch (shape) {\n case 'pill': return 12;\n case 'rounded': return 8;\n case 'sharp': return 2;\n default: return 8;\n }\n}\n\n/**\n * Migrate a v3.0 flat-page EssenceV3 to v3.1 sectioned format.\n * If already v3.1 or has blueprint.sections, returns unchanged.\n */\nexport function migrateV30ToV31(essence: EssenceV3): EssenceV3 {\n if (essence.version === '3.1.0' || essence.blueprint.sections) {\n return essence;\n }\n\n const section: EssenceV31Section = {\n id: essence.meta.archetype,\n role: 'primary',\n shell: essence.blueprint.shell ?? 'top-nav-main',\n features: essence.blueprint.features,\n description: '',\n pages: essence.blueprint.pages ?? [],\n };\n\n return {\n ...essence,\n version: '3.1.0',\n blueprint: {\n ...essence.blueprint,\n sections: [section],\n pages: undefined,\n routes: {},\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/types.ts","../src/validate.ts","../src/density.ts","../src/guard.ts","../src/normalize.ts","../src/migrate.ts"],"sourcesContent":["/**\n * Essence v2 schema types — normalized terminology.\n *\n * Terminology mapping (v1 wine terms → v2 normalized):\n * terroir → archetype, vintage → theme, tannins → features,\n * carafe → shell, cork → guard, blend → layout, clarity → density,\n * vessel → platform, character → personality,\n * decantation process → essence pipeline\n */\n\n// --- Theme ---\n\nexport type ThemeStyle =\n | 'auradecantism'\n | 'clean'\n | 'glassmorphism'\n | 'retro'\n | 'bioluminescent'\n | 'launchpad'\n | 'dopamine'\n | 'editorial'\n | 'liquid-glass'\n | 'prismatic';\n\nexport type ThemeMode = 'light' | 'dark' | 'auto';\nexport type ThemeShape = 'sharp' | 'rounded' | 'pill';\n\nexport interface Theme {\n id: string;\n mode: ThemeMode;\n shape?: ThemeShape;\n}\n\n// --- Platform ---\n\nexport type PlatformType = 'spa' | 'ssr' | 'static';\nexport type RoutingStrategy = 'hash' | 'history' | 'pathname';\n\nexport interface Platform {\n type: PlatformType;\n routing: RoutingStrategy;\n}\n\n// --- Structure ---\n\nexport type ShellType =\n | 'sidebar-main'\n | 'top-nav-main'\n | 'full-bleed'\n | 'dashboard'\n | 'stacked'\n | string;\n\nexport type LayoutItem = string | PatternRef | ColumnLayout;\n\nexport interface PatternRef {\n pattern: string;\n preset?: string;\n as?: string;\n}\n\nexport interface ColumnLayout {\n cols: string[];\n at?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n span?: Record<string, number>;\n // AUTO: Multi-breakpoint grid — array of { at, cols } entries for cascading breakpoints\n breakpoints?: { at: string; cols: number }[];\n // AUTO: \"container\" uses container queries instead of viewport breakpoints\n responsive?: 'viewport' | 'container';\n}\n\nexport interface StructurePage {\n id: string;\n shell: ShellType;\n layout: LayoutItem[];\n surface?: string;\n}\n\n// --- Density ---\n\nexport type DensityLevel = 'compact' | 'comfortable' | 'spacious';\n\nexport interface Density {\n level: DensityLevel;\n content_gap: string;\n}\n\nexport interface SpatialTokens {\n '--d-section-py': string;\n '--d-interactive-py': string;\n '--d-interactive-px': string;\n '--d-surface-p': string;\n '--d-data-py': string;\n '--d-control-py': string;\n '--d-content-gap': string;\n '--d-label-mb': string;\n '--d-label-px': string;\n '--d-section-gap': string;\n '--d-annotation-mt': string;\n}\n\nexport interface SpatialTokenHints {\n section_padding?: string | null;\n density_bias?: number;\n content_gap_shift?: number;\n label_content_gap?: string | null;\n}\n\nexport interface ShellGuidance {\n section_label_treatment?: string;\n section_density?: DensityLevel;\n [key: string]: string | DensityLevel | undefined;\n}\n\n// --- Guard ---\n\nexport type GuardMode = 'creative' | 'guided' | 'strict';\n\nexport interface Guard {\n enforce_style?: boolean;\n mode: GuardMode;\n}\n\n// --- Impression ---\n\nexport interface Impression {\n vibe: string[];\n references: string[];\n density_intent: DensityLevel | string;\n layout_intent: ShellType | string;\n novel_elements: string[];\n}\n\n// --- Generator Target ---\n\nexport type GeneratorTarget = 'decantr' | 'react' | 'vue' | 'svelte' | string;\n\n// --- Accessibility ---\n\nexport type WcagLevel = 'none' | 'A' | 'AA' | 'AAA';\n\nexport type CvdPreference =\n | 'none'\n | 'auto'\n | 'deuteranopia'\n | 'protanopia'\n | 'tritanopia'\n | 'achromatopsia';\n\nexport interface Accessibility {\n wcag_level?: WcagLevel;\n cvd_preference?: CvdPreference;\n}\n\n// --- Essence (simple) ---\n\nexport interface Essence {\n $schema?: string;\n version: string;\n archetype: string;\n theme: Theme;\n personality: string[];\n platform: Platform;\n structure: StructurePage[];\n features: string[];\n density: Density;\n guard: Guard;\n target: GeneratorTarget;\n accessibility?: Accessibility;\n _impression?: Impression;\n}\n\n// --- Essence (sectioned) ---\n\nexport interface EssenceSection {\n id: string;\n path: string;\n archetype: string;\n theme: Theme;\n structure: StructurePage[];\n features?: string[];\n}\n\nexport interface SectionedEssence {\n $schema?: string;\n version: string;\n platform: Platform;\n personality: string[];\n sections: EssenceSection[];\n shared_features?: string[];\n density: Density;\n guard: Guard;\n target: GeneratorTarget;\n accessibility?: Accessibility;\n _impression?: Impression;\n}\n\n// --- Essence v3: DNA/Blueprint/Meta split ---\n\nexport interface EssenceDNA {\n theme: Theme;\n spacing: {\n base_unit: number;\n scale: string;\n density: DensityLevel;\n content_gap: string;\n };\n typography: {\n scale: string;\n heading_weight: number;\n body_weight: number;\n };\n color: {\n palette: string;\n accent_count: number;\n cvd_preference: CvdPreference | string;\n };\n radius: {\n philosophy: ThemeShape | string;\n base: number;\n };\n elevation: {\n system: string;\n max_levels: number;\n };\n motion: {\n preference: string;\n duration_scale: number;\n reduce_motion: boolean;\n timing?: string;\n durations?: Record<string, string>;\n };\n accessibility: {\n wcag_level: WcagLevel;\n focus_visible: boolean;\n skip_nav: boolean;\n };\n personality: string[];\n constraints?: {\n mode?: string;\n typography?: string;\n borders?: string;\n corners?: string;\n shadows?: string;\n effects?: Record<string, string>;\n };\n}\n\n/** Only density and mode may be overridden per-page. DNA axioms like wcag_level and theme.id are never overrideable. */\nexport interface DNAOverrides {\n density?: DensityLevel;\n mode?: ThemeMode;\n}\n\nexport interface BlueprintPage {\n id: string;\n route?: string;\n shell_override?: ShellType | null;\n layout: LayoutItem[];\n patterns?: PatternRef[];\n dna_overrides?: DNAOverrides;\n surface?: string;\n}\n\nexport type ArchetypeRole = 'primary' | 'gateway' | 'public' | 'auxiliary';\n\nexport interface EssenceV31Section {\n id: string;\n role: ArchetypeRole;\n shell: ShellType | string;\n features: string[];\n description: string;\n pages: BlueprintPage[];\n dna_overrides?: DNAOverrides;\n}\n\nexport interface RouteEntry {\n section: string;\n page: string;\n}\n\nexport interface EssenceBlueprint {\n shell?: ShellType | string;\n sections?: EssenceV31Section[];\n pages?: BlueprintPage[];\n features: string[];\n routes?: Record<string, RouteEntry>;\n icon_style?: string;\n avatar_style?: string;\n}\n\nexport interface EssenceV3Guard {\n mode: GuardMode;\n dna_enforcement: 'error' | 'warn' | 'off';\n blueprint_enforcement: 'warn' | 'off';\n}\n\nexport interface EssenceMeta {\n archetype: string;\n target: GeneratorTarget;\n platform: Platform;\n guard: EssenceV3Guard;\n seo?: {\n schema_org?: string[];\n meta_priorities?: string[];\n };\n navigation?: {\n hotkeys?: Array<{ key: string; route?: string; action?: string; label: string }>;\n command_palette?: boolean;\n };\n}\n\nexport interface EssenceV3 {\n $schema?: string;\n version: '3.0.0' | '3.1.0';\n dna: EssenceDNA;\n blueprint: EssenceBlueprint;\n meta: EssenceMeta;\n _impression?: Impression;\n}\n\n// --- Discriminated union ---\n\nexport type EssenceFile = Essence | SectionedEssence | EssenceV3;\n\nexport function isV3(essence: EssenceFile): essence is EssenceV3 {\n return (essence.version === '3.0.0' || essence.version === '3.1.0') && 'dna' in essence && 'blueprint' in essence;\n}\n\n/** Flatten sections into a flat page list (for guards and backward compat). */\nexport function flattenPages(blueprint: EssenceBlueprint): BlueprintPage[] {\n if (blueprint.sections && blueprint.sections.length > 0) {\n return blueprint.sections.flatMap(s =>\n s.pages.map(p => ({\n ...p,\n shell_override: p.shell_override ?? (s.shell !== blueprint.shell ? (s.shell as ShellType) : undefined),\n }))\n );\n }\n return blueprint.pages ?? [];\n}\n\nexport function isSectioned(essence: EssenceFile): essence is SectionedEssence {\n if (isV3(essence)) return false;\n return 'sections' in essence && Array.isArray((essence as SectionedEssence).sections);\n}\n\nexport function isSimple(essence: EssenceFile): essence is Essence {\n if (isV3(essence)) return false;\n return 'archetype' in essence && !('sections' in essence);\n}\n","import Ajv from 'ajv';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst v2SchemaPath = join(__dirname, '..', 'schema', 'essence.v2.json');\nconst v3SchemaPath = join(__dirname, '..', 'schema', 'essence.v3.json');\n\nlet cachedAjv: Ajv | null = null;\nconst validatorCache = new Map<string, ReturnType<Ajv['compile']>>();\n\nfunction getAjv(): Ajv {\n if (!cachedAjv) {\n cachedAjv = new Ajv({ allErrors: true, strict: false, validateSchema: false });\n }\n return cachedAjv;\n}\n\nfunction getValidator(version: 'v2' | 'v3'): ReturnType<Ajv['compile']> | null {\n if (validatorCache.has(version)) return validatorCache.get(version)!;\n\n const schemaPath = version === 'v3' ? v3SchemaPath : v2SchemaPath;\n if (!existsSync(schemaPath)) return null;\n\n const schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));\n const ajv = getAjv();\n const validate = ajv.compile(schema);\n validatorCache.set(version, validate);\n return validate;\n}\n\nfunction detectVersion(data: unknown): 'v2' | 'v3' {\n if (typeof data === 'object' && data !== null && 'version' in data) {\n const v = (data as Record<string, unknown>).version;\n if (v === '3.0.0' || v === '3.1.0') return 'v3';\n }\n return 'v2';\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateEssence(data: unknown): ValidationResult {\n const version = detectVersion(data);\n const validate = getValidator(version);\n\n if (!validate) {\n return { valid: false, errors: [`No schema available for ${version} documents`] };\n }\n\n const valid = validate(data);\n\n if (valid) {\n return { valid: true, errors: [] };\n }\n\n const errors = (validate.errors ?? []).map((err) => {\n const path = err.instancePath || '/';\n const msg = err.message ?? 'unknown error';\n return `${path}: ${msg}`;\n });\n\n return { valid: false, errors };\n}\n","import type { Density, DensityLevel, SpatialTokens, SpatialTokenHints } from './types.js';\n\ninterface SpatialHints {\n density_bias?: number;\n content_gap_shift?: number;\n}\n\ninterface DensityRule {\n traits: string[];\n level: DensityLevel;\n gap: number;\n}\n\nconst RULES: DensityRule[] = [\n { traits: ['tactical', 'dense', 'data-dense', 'utilitarian'], level: 'compact', gap: 3 },\n { traits: ['luxurious', 'premium', 'editorial'], level: 'spacious', gap: 8 },\n { traits: ['playful', 'bouncy', 'expressive'], level: 'comfortable', gap: 5 },\n { traits: ['minimal', 'clean', 'airy'], level: 'spacious', gap: 6 },\n { traits: ['professional', 'modern', 'balanced'], level: 'comfortable', gap: 4 },\n];\n\nconst MIN_GAP = 2;\nconst MAX_GAP = 10;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function computeDensity(\n personality: string[],\n spatialHints?: SpatialHints,\n): Density {\n const lower = personality.map(c => c.toLowerCase());\n\n let level: DensityLevel = 'comfortable';\n let gap = 4;\n\n for (const rule of RULES) {\n if (rule.traits.some(t => lower.includes(t))) {\n level = rule.level;\n gap = rule.gap;\n break;\n }\n }\n\n if (spatialHints?.density_bias) {\n gap += spatialHints.density_bias;\n }\n if (spatialHints?.content_gap_shift) {\n gap += spatialHints.content_gap_shift;\n }\n\n gap = clamp(gap, MIN_GAP, MAX_GAP);\n\n if (gap <= 3) level = 'compact';\n else if (gap >= 6) level = 'spacious';\n else level = 'comfortable';\n\n return { level, content_gap: String(gap) };\n}\n\n// --- Spatial Tokens ---\n\nconst DENSITY_SCALES: Record<DensityLevel, number> = {\n compact: 0.65,\n comfortable: 1.0,\n spacious: 1.4,\n};\n\nconst BASE_TOKENS = {\n '--d-section-py': 5,\n '--d-interactive-py': 0.5,\n '--d-interactive-px': 1,\n '--d-surface-p': 1.25,\n '--d-data-py': 0.625,\n '--d-control-py': 0.5,\n '--d-content-gap': 1,\n '--d-label-mb': 0.75,\n '--d-label-px': 0.75,\n '--d-section-gap': 1.5,\n '--d-annotation-mt': 0.5,\n} as const;\n\nfunction roundTo3(value: number): number {\n return Math.round(value * 1000) / 1000;\n}\n\nfunction toRemString(value: number): string {\n const rounded = roundTo3(value);\n return `${rounded}rem`;\n}\n\nexport function computeSpatialTokens(\n density: DensityLevel,\n spatialHints?: SpatialTokenHints,\n): SpatialTokens {\n const scale = DENSITY_SCALES[density];\n const biasMultiplier = 1 + (spatialHints?.density_bias ?? 0) / 10;\n\n const result = {} as SpatialTokens;\n\n for (const [key, base] of Object.entries(BASE_TOKENS)) {\n const tokenKey = key as keyof SpatialTokens;\n\n // --d-label-px is a visual anchor — never density-scaled\n if (tokenKey === '--d-label-px') {\n result[tokenKey] = toRemString(base);\n continue;\n }\n\n if (tokenKey === '--d-section-py' && spatialHints?.section_padding) {\n const pxMatch = spatialHints.section_padding.match(/^(\\d+(?:\\.\\d+)?)px$/);\n if (pxMatch) {\n const remValue = parseFloat(pxMatch[1]) / 16;\n result[tokenKey] = toRemString(remValue * scale * biasMultiplier);\n continue;\n }\n const remMatch = spatialHints.section_padding.match(/^(\\d+(?:\\.\\d+)?)rem$/);\n if (remMatch) {\n const remValue = parseFloat(remMatch[1]);\n result[tokenKey] = toRemString(remValue * scale * biasMultiplier);\n continue;\n }\n }\n\n // --d-label-mb can be overridden by theme's label_content_gap\n if (tokenKey === '--d-label-mb' && spatialHints?.label_content_gap) {\n const remMatch = spatialHints.label_content_gap.match(/^(\\d+(?:\\.\\d+)?)rem$/);\n if (remMatch) {\n const remValue = parseFloat(remMatch[1]);\n result[tokenKey] = toRemString(remValue * scale * biasMultiplier);\n continue;\n }\n }\n\n let computed = base * scale * biasMultiplier;\n\n if (tokenKey === '--d-content-gap' && spatialHints?.content_gap_shift) {\n computed += spatialHints.content_gap_shift * 0.25;\n }\n\n result[tokenKey] = toRemString(computed);\n }\n\n return result;\n}\n","import type { EssenceFile, EssenceV3, EssenceV3Guard, StructurePage, LayoutItem, DensityLevel } from './types.js';\nimport { isSimple, isSectioned, isV3, flattenPages } from './types.js';\n\nexport interface AutoFix {\n type: 'add_page' | 'update_layout' | 'update_blueprint';\n patch: Record<string, unknown>;\n}\n\nexport interface GuardViolation {\n rule: 'theme' | 'structure' | 'layout' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility';\n severity: 'error' | 'warning';\n message: string;\n suggestion?: string;\n layer?: 'dna' | 'blueprint';\n autoFixable?: boolean;\n autoFix?: AutoFix;\n}\n\nexport interface GuardContext {\n pageId?: string;\n theme?: string;\n /** @deprecated Use `theme` instead. */\n style?: string;\n layout?: string[];\n density_gap?: string;\n themeRegistry?: Map<string, { modes: string[] }>;\n patternRegistry?: Map<string, unknown>;\n a11y_issues?: string[];\n}\n\n/**\n * Check if the theme supports the specified mode.\n */\nfunction checkThemeModeCompatibility(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation | null {\n if (!context.themeRegistry) return null;\n\n let themeId: string | null;\n let mode: string | null;\n if (isV3(essence)) {\n themeId = essence.dna.theme?.id ?? null;\n mode = essence.dna.theme?.mode ?? null;\n } else {\n themeId = isSimple(essence) ? essence.theme?.id : null;\n mode = isSimple(essence) ? essence.theme?.mode : null;\n }\n\n if (!themeId || !mode) return null;\n\n const theme = context.themeRegistry.get(themeId);\n if (!theme) {\n // Theme not found - separate validation\n return null;\n }\n\n if (!theme.modes.includes(mode) && mode !== 'auto') {\n const supportedModes = theme.modes.join(', ');\n const suggestion = theme.modes.length > 0\n ? `Use mode: \"${theme.modes[0]}\" instead, or choose a theme that supports ${mode} mode.`\n : undefined;\n\n return {\n rule: 'theme-mode',\n severity: 'error',\n message: `Theme \"${themeId}\" does not support \"${mode}\" mode. Supported modes: ${supportedModes}.`,\n suggestion,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n };\n }\n\n return null;\n}\n\n/**\n * Collect all pattern IDs from a layout item, recursively handling nested structures.\n */\nfunction collectPatternIds(item: LayoutItem, ids: Set<string>): void {\n if (typeof item === 'string') {\n ids.add(item);\n return;\n }\n if (typeof item === 'object' && item !== null) {\n if ('pattern' in item && typeof item.pattern === 'string') {\n ids.add(item.pattern);\n }\n if ('cols' in item && Array.isArray(item.cols)) {\n for (const col of item.cols) {\n // cols contains strings (pattern IDs)\n if (typeof col === 'string') {\n ids.add(col);\n }\n }\n }\n }\n}\n\n/**\n * Find similar pattern IDs in the registry for suggestion.\n */\nfunction findSimilarPatterns(target: string, registry: Map<string, unknown>): string[] {\n const similar: string[] = [];\n const targetLower = target.toLowerCase();\n\n for (const id of registry.keys()) {\n const idLower = id.toLowerCase();\n // Simple similarity: contains target or target contains id\n if (idLower.includes(targetLower) || targetLower.includes(idLower)) {\n similar.push(id);\n }\n }\n\n return similar.slice(0, 3); // Top 3 suggestions\n}\n\n/**\n * Check if all referenced patterns exist in the registry.\n */\nfunction checkPatternExistence(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation[] {\n if (!context.patternRegistry) return [];\n\n const violations: GuardViolation[] = [];\n const referencedPatterns = new Set<string>();\n\n // Collect all pattern references from structure\n const pages = getAllPages(essence);\n for (const page of pages) {\n for (const item of page.layout || []) {\n collectPatternIds(item, referencedPatterns);\n }\n }\n\n // Check each pattern exists\n for (const patternId of referencedPatterns) {\n if (!context.patternRegistry.has(patternId)) {\n // Find similar patterns for suggestion\n const similar = findSimilarPatterns(patternId, context.patternRegistry);\n const suggestion = similar.length > 0\n ? `Similar patterns: ${similar.join(', ')}`\n : `Run \"decantr search ${patternId}\" to find alternatives.`;\n\n violations.push({\n rule: 'pattern-exists',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Pattern \"${patternId}\" is referenced but does not exist in the registry.`,\n suggestion,\n ...(isV3(essence) ? { layer: 'blueprint' as const, autoFixable: false } : {}),\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Check accessibility compliance based on declared WCAG level.\n */\nfunction checkAccessibility(\n essence: EssenceFile,\n context: GuardContext\n): GuardViolation | null {\n const accessibility = isV3(essence) ? essence.dna.accessibility : ('accessibility' in essence ? essence.accessibility : undefined);\n\n if (!accessibility?.wcag_level || accessibility.wcag_level === 'none') {\n return null;\n }\n\n if (context.a11y_issues && context.a11y_issues.length > 0) {\n const issueList = context.a11y_issues.slice(0, 3).join(', ');\n const moreCount = context.a11y_issues.length > 3 ? ` (+${context.a11y_issues.length - 3} more)` : '';\n\n return {\n rule: 'accessibility',\n severity: 'error',\n message: `WCAG ${accessibility.wcag_level} compliance required. Issues found: ${issueList}${moreCount}`,\n suggestion: 'Fix accessibility issues before proceeding. Run an accessibility audit for details.',\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n };\n }\n\n return null;\n}\n\nexport function evaluateGuard(essence: EssenceFile, context: GuardContext = {}): GuardViolation[] {\n const guard = isV3(essence) ? essence.meta.guard : essence.guard;\n\n if (guard.mode === 'creative') {\n return [];\n }\n\n const violations: GuardViolation[] = [];\n const isStrict = guard.mode === 'strict';\n\n // Rule 1: Theme guard\n const requestedTheme = context.theme ?? context.style;\n if (requestedTheme) {\n let essenceThemeId: string | null;\n if (isV3(essence)) {\n essenceThemeId = essence.dna.theme.id;\n } else {\n essenceThemeId = isSimple(essence) ? essence.theme.id : null;\n }\n const enforceStyle = isV3(essence) ? true : (guard as import('./types.js').Guard).enforce_style !== false;\n if (essenceThemeId && requestedTheme !== essenceThemeId && enforceStyle) {\n violations.push({\n rule: 'theme',\n severity: 'error',\n message: `Theme \"${requestedTheme}\" does not match essence theme \"${essenceThemeId}\". Change the essence theme first.`,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n });\n }\n }\n\n // Rule 2: Structure guard (enforced in both guided and strict)\n if (context.pageId) {\n const pages = getAllPages(essence);\n const pageExists = pages.some(p => p.id === context.pageId);\n if (!pageExists) {\n violations.push({\n rule: 'structure',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Page \"${context.pageId}\" does not exist in essence structure. Add it to the essence first.`,\n ...(isV3(essence) ? {\n layer: 'blueprint' as const,\n autoFixable: true,\n autoFix: { type: 'add_page' as const, patch: { id: context.pageId } },\n } : {}),\n });\n }\n }\n\n // Rule 3: Layout guard (strict only)\n if (isStrict && context.pageId && context.layout) {\n const pages = getAllPages(essence);\n const page = pages.find(p => p.id === context.pageId);\n if (page) {\n const essenceLayout = page.layout.map(item =>\n typeof item === 'string' ? item : 'pattern' in item ? item.pattern : 'cols'\n );\n const proposedLayout = context.layout;\n const matches = essenceLayout.length === proposedLayout.length &&\n essenceLayout.every((item, i) => item === proposedLayout[i]);\n if (!matches) {\n violations.push({\n rule: 'layout',\n severity: isV3(essence) ? 'warning' : 'error',\n message: `Layout for page \"${context.pageId}\" deviates from essence. Expected: [${essenceLayout.join(', ')}].`,\n ...(isV3(essence) ? {\n layer: 'blueprint' as const,\n autoFixable: true,\n autoFix: { type: 'update_layout' as const, patch: { page: context.pageId, layout: context.layout } },\n } : {}),\n });\n }\n }\n }\n\n // Rule 4: Density guard (strict only)\n if (isStrict && context.density_gap) {\n let expectedGap: string;\n if (isV3(essence)) {\n // Check per-page dna_overrides for density if a pageId is provided\n const overriddenDensity = getPageDensityOverride(essence, context.pageId);\n expectedGap = overriddenDensity ?? essence.dna.spacing.content_gap;\n } else {\n expectedGap = essence.density.content_gap;\n }\n if (context.density_gap !== expectedGap) {\n violations.push({\n rule: 'density',\n severity: 'warning',\n message: `Content gap \"${context.density_gap}\" does not match essence density \"${expectedGap}\".`,\n ...(isV3(essence) ? { layer: 'dna' as const, autoFixable: false } : {}),\n });\n }\n }\n\n // Rule 6: Theme/mode compatibility (always checked when registry available)\n const themeModeViolation = checkThemeModeCompatibility(essence, context);\n if (themeModeViolation) {\n violations.push(themeModeViolation);\n }\n\n // Rule 7: Pattern existence (always checked when registry available)\n const patternViolations = checkPatternExistence(essence, context);\n violations.push(...patternViolations);\n\n // Rule 8: Accessibility (when wcag_level is set, guided and strict modes)\n const accessibilityViolation = checkAccessibility(essence, context);\n if (accessibilityViolation) {\n violations.push(accessibilityViolation);\n }\n\n // Apply v3 enforcement level filtering\n if (isV3(essence)) {\n const v3Guard = guard as EssenceV3Guard;\n\n // DNA enforcement\n if (v3Guard.dna_enforcement === 'off') {\n // Remove all DNA-layer violations\n return violations.filter(v => v.layer !== 'dna');\n }\n if (v3Guard.dna_enforcement === 'warn') {\n // Downgrade DNA-layer violations to warning severity\n for (const v of violations) {\n if (v.layer === 'dna') {\n v.severity = 'warning';\n }\n }\n }\n\n // Blueprint enforcement\n if (v3Guard.blueprint_enforcement === 'off') {\n // Remove all blueprint-layer violations\n return violations.filter(v => v.layer !== 'blueprint');\n }\n }\n\n return violations;\n}\n\nfunction getAllPages(essence: EssenceFile): StructurePage[] {\n if (isV3(essence)) {\n // Map v3 BlueprintPages to StructurePage shape for guard evaluation\n const pages = flattenPages(essence.blueprint);\n return pages.map(page => ({\n id: page.id,\n shell: page.shell_override ?? essence.blueprint.shell ?? '',\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n }));\n }\n if (isSimple(essence)) return essence.structure;\n if (isSectioned(essence)) return essence.sections.flatMap(s => s.structure);\n throw new Error('Unknown EssenceFile type');\n}\n\n/** Get per-page density override from v3 blueprint, if set. */\nfunction getPageDensityOverride(essence: EssenceV3, pageId?: string): string | undefined {\n if (!pageId) return undefined;\n const pages = flattenPages(essence.blueprint);\n const page = pages.find(p => p.id === pageId);\n if (!page?.dna_overrides?.density) return undefined;\n // Map density level to a content_gap value\n const densityGapMap: Record<DensityLevel, string> = {\n compact: '2',\n comfortable: '4',\n spacious: '6',\n };\n return densityGapMap[page.dna_overrides.density] ?? undefined;\n}\n","import type { Essence, SectionedEssence, EssenceFile, EssenceV3, StructurePage, GuardMode } from './types.js';\n\nexport function normalizeEssence(input: Record<string, unknown>): EssenceFile {\n // v3: version-based detection only (no structural fallback to avoid false positives)\n if (input.version === '3.0.0' || input.version === '3.1.0') {\n return input as unknown as EssenceV3;\n }\n\n // Detect v2: has 'theme' and 'platform' (normalized terms)\n if (input.theme && input.platform) {\n return input as unknown as EssenceFile;\n }\n\n if (input.sections) {\n return normalizeSectioned(input);\n }\n\n return normalizeSimple(input);\n}\n\nfunction normalizeSimple(v1: Record<string, unknown>): Essence {\n // v1 field names (wine terms) → v2 normalized names:\n // vintage → theme, vessel → platform, clarity → density,\n // cork → guard, terroir/vignette → archetype, tannins → features,\n // carafe → shell, blend → layout, character → personality\n const vintage = v1.vintage as Record<string, string> | undefined;\n const vessel = v1.vessel as Record<string, string> | undefined;\n const clarity = v1.clarity as Record<string, string> | undefined;\n const cork = v1.cork as Record<string, unknown> | undefined;\n const structure = v1.structure as Array<Record<string, unknown>> | undefined;\n\n return {\n version: '2.0.0',\n archetype: (v1.terroir ?? v1.vignette ?? v1.archetype) as string,\n theme: {\n id: vintage?.style ?? '',\n mode: (vintage?.mode ?? 'dark') as 'light' | 'dark' | 'auto',\n ...(vintage?.shape ? { shape: vintage.shape as 'sharp' | 'rounded' | 'pill' } : {}),\n },\n // Accept both old 'character' and new 'personality' field names\n personality: (v1.character ?? v1.personality) as string[],\n platform: {\n type: (vessel?.type ?? 'spa') as 'spa' | 'ssr' | 'static',\n routing: (vessel?.routing ?? 'hash') as 'hash' | 'history' | 'pathname',\n },\n structure: (structure ?? []).map(normalizeStructurePage),\n features: (v1.tannins ?? v1.features ?? []) as string[],\n density: {\n level: (clarity?.density ?? 'comfortable') as 'compact' | 'comfortable' | 'spacious',\n content_gap: stripGapPrefix(clarity?.content_gap ?? '4'),\n },\n guard: normalizeGuard(cork),\n target: (v1.target as string) ?? 'decantr',\n ...(v1._impression ? { _impression: v1._impression as Essence['_impression'] } : {}),\n };\n}\n\nfunction normalizeSectioned(v1: Record<string, unknown>): SectionedEssence {\n // v1 field names (wine terms) → v2 normalized names:\n // vessel → platform, clarity → density, cork → guard,\n // terroir/vignette → archetype, tannins → features,\n // shared_tannins → shared_features, character → personality\n const vessel = v1.vessel as Record<string, string> | undefined;\n const clarity = v1.clarity as Record<string, string> | undefined;\n const cork = v1.cork as Record<string, unknown> | undefined;\n const sections = v1.sections as Array<Record<string, unknown>>;\n\n return {\n version: '2.0.0',\n platform: {\n type: (vessel?.type ?? 'spa') as 'spa' | 'ssr' | 'static',\n routing: (vessel?.routing ?? 'hash') as 'hash' | 'history' | 'pathname',\n },\n // Accept both old 'character' and new 'personality' field names\n personality: (v1.character ?? v1.personality) as string[],\n sections: sections.map(section => ({\n id: section.id as string,\n path: section.path as string,\n archetype: (section.terroir ?? section.vignette ?? section.archetype) as string,\n theme: {\n id: (section.vintage as Record<string, string>)?.style ?? '',\n mode: ((section.vintage as Record<string, string>)?.mode ?? 'dark') as 'light' | 'dark' | 'auto',\n },\n structure: ((section.structure as Array<Record<string, unknown>>) ?? []).map(normalizeStructurePage),\n ...(section.tannins ? { features: section.tannins as string[] } : {}),\n })),\n ...(v1.shared_tannins ? { shared_features: v1.shared_tannins as string[] } : {}),\n density: {\n level: (clarity?.density ?? 'comfortable') as 'compact' | 'comfortable' | 'spacious',\n content_gap: stripGapPrefix(clarity?.content_gap ?? '4'),\n },\n guard: normalizeGuard(cork),\n target: (v1.target as string) ?? 'decantr',\n };\n}\n\nfunction normalizeStructurePage(page: Record<string, unknown>): StructurePage {\n // Accept v1 wine terms (carafe → shell, blend → layout) for backward compatibility\n return {\n id: page.id as string,\n shell: (page.carafe ?? page.shell) as string,\n layout: (page.blend ?? page.layout) as StructurePage['layout'],\n ...(page.surface ? { surface: page.surface as string } : {}),\n };\n}\n\n// Accept v1 'cork' object and normalize to v2 'guard'\nfunction normalizeGuard(cork: Record<string, unknown> | undefined): Essence['guard'] {\n if (!cork) return { mode: 'creative' };\n\n const modeMap: Record<string, GuardMode> = {\n creative: 'creative',\n maintenance: 'strict',\n strict: 'strict',\n guided: 'guided',\n };\n\n return {\n ...(cork.enforce_style !== undefined ? { enforce_style: cork.enforce_style as boolean } : {}),\n mode: modeMap[(cork.mode as string) ?? 'creative'] ?? 'creative',\n };\n}\n\nfunction stripGapPrefix(gap: string): string {\n const match = gap.match(/^_gap(\\d+)$/);\n return match ? match[1] : gap;\n}\n","import type {\n Essence,\n SectionedEssence,\n EssenceV3,\n EssenceFile,\n EssenceDNA,\n EssenceBlueprint,\n EssenceMeta,\n EssenceV31Section,\n ThemeShape,\n DensityLevel,\n GuardMode,\n} from './types.js';\nimport { isSimple, isSectioned, isV3 } from './types.js';\n\n/**\n * Migrate a v2 EssenceFile to v3 format (DNA/Blueprint/Meta split).\n * If already v3, returns unchanged. SectionedEssence uses first section's theme.\n */\nexport function migrateV2ToV3(essence: EssenceFile): EssenceV3 {\n if (isV3(essence)) return essence;\n\n if (isSectioned(essence)) {\n return migrateSectionedToV3(essence);\n }\n\n if (isSimple(essence)) {\n return migrateSimpleToV3(essence);\n }\n\n throw new Error('Unknown EssenceFile type — cannot migrate');\n}\n\nfunction migrateSimpleToV3(essence: Essence): EssenceV3 {\n const dna = buildDNA(essence);\n const blueprint = buildBlueprintFromSimple(essence);\n const meta = buildMeta(essence);\n\n return {\n version: '3.0.0',\n dna,\n blueprint,\n meta,\n ...(essence._impression ? { _impression: essence._impression } : {}),\n };\n}\n\nfunction migrateSectionedToV3(essence: SectionedEssence): EssenceV3 {\n // Use first section's theme as the DNA theme (sectioned essences have per-section themes)\n const firstSection = essence.sections[0];\n const syntheticSimple: Partial<Essence> = {\n theme: firstSection.theme,\n density: essence.density,\n guard: essence.guard,\n accessibility: essence.accessibility,\n };\n\n const dna = buildDNA(syntheticSimple as Essence);\n // Override personality from the sectioned root\n dna.personality = essence.personality;\n\n // Flatten all sections' pages into the blueprint\n const pages = essence.sections.flatMap(section =>\n section.structure.map(page => ({\n id: page.id,\n shell_override: page.shell as string | null,\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n }))\n );\n\n const allFeatures = [\n ...(essence.shared_features ?? []),\n ...essence.sections.flatMap(s => s.features ?? []),\n ];\n\n const blueprint: EssenceBlueprint = {\n shell: firstSection.structure[0]?.shell ?? 'top-nav-main',\n pages,\n features: [...new Set(allFeatures)],\n };\n\n const meta: EssenceMeta = {\n archetype: firstSection.archetype,\n target: essence.target,\n platform: essence.platform,\n guard: migrateGuard(essence.guard.mode),\n };\n\n return {\n version: '3.0.0',\n dna,\n blueprint,\n meta,\n ...(essence._impression ? { _impression: essence._impression } : {}),\n };\n}\n\nfunction buildDNA(essence: Essence): EssenceDNA {\n const shape = essence.theme.shape ?? 'rounded';\n const radiusBase = inferRadiusBase(shape);\n\n return {\n theme: {\n id: essence.theme.id,\n mode: essence.theme.mode,\n ...(essence.theme.shape ? { shape: essence.theme.shape } : {}),\n },\n spacing: {\n base_unit: 4,\n scale: 'linear',\n density: (essence.density?.level ?? 'comfortable') as DensityLevel,\n content_gap: essence.density?.content_gap ?? '4',\n },\n typography: {\n scale: 'modular',\n heading_weight: 600,\n body_weight: 400,\n },\n color: {\n palette: 'semantic',\n accent_count: 1,\n cvd_preference: essence.accessibility?.cvd_preference ?? 'auto',\n },\n radius: {\n philosophy: shape,\n base: radiusBase,\n },\n elevation: {\n system: 'layered',\n max_levels: 3,\n },\n motion: {\n preference: 'subtle',\n duration_scale: 1.0,\n reduce_motion: true,\n },\n accessibility: {\n wcag_level: essence.accessibility?.wcag_level ?? 'AA',\n focus_visible: true,\n skip_nav: true,\n },\n personality: essence.personality ?? ['professional'],\n };\n}\n\nfunction buildBlueprintFromSimple(essence: Essence): EssenceBlueprint {\n const defaultShell = essence.structure[0]?.shell ?? 'top-nav-main';\n\n return {\n shell: defaultShell,\n pages: essence.structure.map(page => ({\n id: page.id,\n ...(page.shell !== defaultShell ? { shell_override: page.shell } : {}),\n layout: page.layout,\n ...(page.surface ? { surface: page.surface } : {}),\n })),\n features: essence.features ?? [],\n };\n}\n\nfunction buildMeta(essence: Essence): EssenceMeta {\n return {\n archetype: essence.archetype,\n target: essence.target,\n platform: essence.platform,\n guard: migrateGuard(essence.guard.mode),\n };\n}\n\nfunction migrateGuard(mode: GuardMode): EssenceMeta['guard'] {\n switch (mode) {\n case 'strict':\n return { mode: 'strict', dna_enforcement: 'error', blueprint_enforcement: 'warn' };\n case 'guided':\n return { mode: 'guided', dna_enforcement: 'error', blueprint_enforcement: 'off' };\n case 'creative':\n default:\n return { mode: 'creative', dna_enforcement: 'off', blueprint_enforcement: 'off' };\n }\n}\n\nfunction inferRadiusBase(shape: ThemeShape | string): number {\n switch (shape) {\n case 'pill': return 12;\n case 'rounded': return 8;\n case 'sharp': return 2;\n default: return 8;\n }\n}\n\n/**\n * Migrate a v3.0 flat-page EssenceV3 to v3.1 sectioned format.\n * If already v3.1 or has blueprint.sections, returns unchanged.\n */\nexport function migrateV30ToV31(essence: EssenceV3): EssenceV3 {\n if (essence.version === '3.1.0' || essence.blueprint.sections) {\n return essence;\n }\n\n const section: EssenceV31Section = {\n id: essence.meta.archetype,\n role: 'primary',\n shell: essence.blueprint.shell ?? 'top-nav-main',\n features: essence.blueprint.features,\n description: `${essence.meta.archetype} primary section`,\n pages: essence.blueprint.pages ?? [],\n };\n\n return {\n ...essence,\n version: '3.1.0',\n blueprint: {\n ...essence.blueprint,\n sections: [section],\n pages: undefined,\n routes: {},\n },\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@decantr/essence-spec",
3
- "version": "1.0.0-beta.9",
4
- "description": "Essence schema, validator, and TypeScript types for Decantr",
3
+ "version": "1.0.1",
4
+ "description": "Essence schemas, validation, migration, and TypeScript types for Decantr",
5
+ "author": "Decantr AI",
5
6
  "license": "MIT",
7
+ "bugs": {
8
+ "url": "https://github.com/decantr-ai/decantr/issues"
9
+ },
6
10
  "repository": {
7
11
  "type": "git",
8
- "url": "https://github.com/decantr-ai/decantr.git",
12
+ "url": "git+https://github.com/decantr-ai/decantr.git",
9
13
  "directory": "packages/essence-spec"
10
14
  },
11
15
  "homepage": "https://decantr.ai",
@@ -19,18 +23,23 @@
19
23
  },
20
24
  "./schema": {
21
25
  "import": "./schema/essence.v2.json"
22
- }
26
+ },
27
+ "./schema/essence.v2.json": "./schema/essence.v2.json",
28
+ "./schema/essence.v3.json": "./schema/essence.v3.json"
23
29
  },
24
- "files": ["dist", "schema"],
30
+ "files": [
31
+ "dist",
32
+ "schema"
33
+ ],
25
34
  "publishConfig": {
26
35
  "access": "public"
27
36
  },
37
+ "dependencies": {
38
+ "ajv": "^8.17.0"
39
+ },
28
40
  "scripts": {
29
41
  "build": "tsup",
30
42
  "test": "vitest run",
31
43
  "test:watch": "vitest"
32
- },
33
- "dependencies": {
34
- "ajv": "^8.17.0"
35
44
  }
36
- }
45
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://decantr.ai/schema/essence/2.0.json",
3
+ "$id": "https://decantr.ai/schemas/essence.v2.json",
4
4
  "title": "Decantr Essence v2",
5
5
  "description": "Design intent specification for AI-generated web applications",
6
6
  "oneOf": [
@@ -48,12 +48,11 @@
48
48
  },
49
49
  "Theme": {
50
50
  "type": "object",
51
- "required": ["style", "mode", "recipe"],
51
+ "required": ["id", "mode"],
52
52
  "additionalProperties": false,
53
53
  "properties": {
54
- "style": { "type": "string", "minLength": 1 },
54
+ "id": { "type": "string", "minLength": 1 },
55
55
  "mode": { "type": "string", "enum": ["light", "dark", "auto"] },
56
- "recipe": { "type": "string", "minLength": 1 },
57
56
  "shape": { "type": "string", "enum": ["sharp", "rounded", "pill"] }
58
57
  }
59
58
  },
@@ -63,7 +62,7 @@
63
62
  "additionalProperties": false,
64
63
  "properties": {
65
64
  "type": { "type": "string", "enum": ["spa", "ssr", "static"] },
66
- "routing": { "type": "string", "enum": ["hash", "history"] }
65
+ "routing": { "type": "string", "enum": ["hash", "history", "pathname"] }
67
66
  }
68
67
  },
69
68
  "StructurePage": {
@@ -121,7 +120,6 @@
121
120
  "additionalProperties": false,
122
121
  "properties": {
123
122
  "enforce_style": { "type": "boolean" },
124
- "enforce_recipe": { "type": "boolean" },
125
123
  "mode": { "type": "string", "enum": ["creative", "guided", "strict"] }
126
124
  }
127
125
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://decantr.ai/schema/essence/3.0.json",
3
+ "$id": "https://decantr.ai/schemas/essence.v3.json",
4
4
  "title": "Decantr Essence v3",
5
5
  "description": "Design intent specification with DNA/Blueprint/Meta split",
6
6
  "type": "object",
@@ -8,7 +8,7 @@
8
8
  "additionalProperties": false,
9
9
  "properties": {
10
10
  "$schema": { "type": "string" },
11
- "version": { "type": "string", "const": "3.0.0" },
11
+ "version": { "type": "string", "enum": ["3.0.0", "3.1.0"] },
12
12
  "dna": { "$ref": "#/$defs/DNA" },
13
13
  "blueprint": { "$ref": "#/$defs/Blueprint" },
14
14
  "meta": { "$ref": "#/$defs/Meta" },
@@ -28,17 +28,17 @@
28
28
  "elevation": { "$ref": "#/$defs/Elevation" },
29
29
  "motion": { "$ref": "#/$defs/Motion" },
30
30
  "accessibility": { "$ref": "#/$defs/AccessibilityV3" },
31
- "personality": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
31
+ "personality": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
32
+ "constraints": { "$ref": "#/$defs/Constraints" }
32
33
  }
33
34
  },
34
35
  "Theme": {
35
36
  "type": "object",
36
- "required": ["style", "mode", "recipe"],
37
+ "required": ["id", "mode"],
37
38
  "additionalProperties": false,
38
39
  "properties": {
39
- "style": { "type": "string", "minLength": 1 },
40
+ "id": { "type": "string", "minLength": 1 },
40
41
  "mode": { "type": "string", "enum": ["light", "dark", "auto"] },
41
- "recipe": { "type": "string", "minLength": 1 },
42
42
  "shape": { "type": "string", "enum": ["sharp", "rounded", "pill"] }
43
43
  }
44
44
  },
@@ -111,14 +111,38 @@
111
111
  "skip_nav": { "type": "boolean" }
112
112
  }
113
113
  },
114
+ "Constraints": {
115
+ "type": "object",
116
+ "additionalProperties": false,
117
+ "properties": {
118
+ "mode": { "type": "string", "minLength": 1 },
119
+ "typography": { "type": "string", "minLength": 1 },
120
+ "borders": { "type": "string", "minLength": 1 },
121
+ "corners": { "type": "string", "minLength": 1 },
122
+ "shadows": { "type": "string", "minLength": 1 },
123
+ "effects": {
124
+ "type": "object",
125
+ "additionalProperties": { "type": "string" }
126
+ }
127
+ }
128
+ },
114
129
  "Blueprint": {
115
130
  "type": "object",
116
- "required": ["shell", "pages", "features"],
131
+ "required": ["features"],
117
132
  "additionalProperties": false,
133
+ "anyOf": [
134
+ { "required": ["shell", "pages"] },
135
+ { "required": ["sections"] }
136
+ ],
118
137
  "properties": {
119
138
  "shell": { "type": "string", "minLength": 1 },
120
139
  "pages": { "type": "array", "items": { "$ref": "#/$defs/BlueprintPage" }, "minItems": 1 },
140
+ "sections": { "type": "array", "items": { "$ref": "#/$defs/BlueprintSection" }, "minItems": 1 },
121
141
  "features": { "type": "array", "items": { "type": "string" } },
142
+ "routes": {
143
+ "type": "object",
144
+ "additionalProperties": { "$ref": "#/$defs/RouteEntry" }
145
+ },
122
146
  "icon_style": { "type": "string" },
123
147
  "avatar_style": { "type": "string" }
124
148
  }
@@ -129,12 +153,36 @@
129
153
  "additionalProperties": false,
130
154
  "properties": {
131
155
  "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
156
+ "route": { "type": "string", "minLength": 1 },
132
157
  "shell_override": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
133
158
  "layout": { "type": "array", "items": { "$ref": "#/$defs/LayoutItem" }, "minItems": 1 },
134
159
  "dna_overrides": { "$ref": "#/$defs/DNAOverrides" },
135
160
  "surface": { "type": "string" }
136
161
  }
137
162
  },
163
+ "BlueprintSection": {
164
+ "type": "object",
165
+ "required": ["id", "role", "shell", "features", "description", "pages"],
166
+ "additionalProperties": false,
167
+ "properties": {
168
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
169
+ "role": { "type": "string", "enum": ["primary", "gateway", "public", "auxiliary"] },
170
+ "shell": { "type": "string", "minLength": 1 },
171
+ "features": { "type": "array", "items": { "type": "string" } },
172
+ "description": { "type": "string", "minLength": 1 },
173
+ "pages": { "type": "array", "items": { "$ref": "#/$defs/BlueprintPage" }, "minItems": 1 },
174
+ "dna_overrides": { "$ref": "#/$defs/DNAOverrides" }
175
+ }
176
+ },
177
+ "RouteEntry": {
178
+ "type": "object",
179
+ "required": ["section", "page"],
180
+ "additionalProperties": false,
181
+ "properties": {
182
+ "section": { "type": "string", "minLength": 1 },
183
+ "page": { "type": "string", "minLength": 1 }
184
+ }
185
+ },
138
186
  "DNAOverrides": {
139
187
  "type": "object",
140
188
  "additionalProperties": false,
@@ -180,7 +228,9 @@
180
228
  "archetype": { "type": "string", "minLength": 1 },
181
229
  "target": { "type": "string", "minLength": 1 },
182
230
  "platform": { "$ref": "#/$defs/Platform" },
183
- "guard": { "$ref": "#/$defs/GuardV3" }
231
+ "guard": { "$ref": "#/$defs/GuardV3" },
232
+ "seo": { "$ref": "#/$defs/SeoHints" },
233
+ "navigation": { "$ref": "#/$defs/NavigationHints" }
184
234
  }
185
235
  },
186
236
  "Platform": {
@@ -189,7 +239,7 @@
189
239
  "additionalProperties": false,
190
240
  "properties": {
191
241
  "type": { "type": "string", "enum": ["spa", "ssr", "static"] },
192
- "routing": { "type": "string", "enum": ["hash", "history"] }
242
+ "routing": { "type": "string", "enum": ["hash", "history", "pathname"] }
193
243
  }
194
244
  },
195
245
  "GuardV3": {
@@ -202,6 +252,33 @@
202
252
  "blueprint_enforcement": { "type": "string", "enum": ["warn", "off"] }
203
253
  }
204
254
  },
255
+ "SeoHints": {
256
+ "type": "object",
257
+ "additionalProperties": false,
258
+ "properties": {
259
+ "schema_org": { "type": "array", "items": { "type": "string", "minLength": 1 } },
260
+ "meta_priorities": { "type": "array", "items": { "type": "string", "minLength": 1 } }
261
+ }
262
+ },
263
+ "NavigationHints": {
264
+ "type": "object",
265
+ "additionalProperties": false,
266
+ "properties": {
267
+ "hotkeys": { "type": "array", "items": { "$ref": "#/$defs/NavigationHotkey" } },
268
+ "command_palette": { "type": "boolean" }
269
+ }
270
+ },
271
+ "NavigationHotkey": {
272
+ "type": "object",
273
+ "required": ["key", "label"],
274
+ "additionalProperties": false,
275
+ "properties": {
276
+ "key": { "type": "string", "minLength": 1 },
277
+ "label": { "type": "string", "minLength": 1 },
278
+ "route": { "type": "string", "minLength": 1 },
279
+ "action": { "type": "string", "minLength": 1 }
280
+ }
281
+ },
205
282
  "Impression": {
206
283
  "type": "object",
207
284
  "additionalProperties": false,