@decantr/essence-spec 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +115 -12
- package/dist/index.js +234 -179
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/schema/essence.v3.json +25 -2
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,15 @@ interface PatternRef {
|
|
|
29
29
|
as?: string;
|
|
30
30
|
}
|
|
31
31
|
interface ColumnLayout {
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Column entries. Each entry is either a pattern id string OR a
|
|
34
|
+
* PatternRef object with `pattern`, optional `preset`, and optional
|
|
35
|
+
* `as` alias. Mixing the two forms is permitted by the schema.
|
|
36
|
+
* Consumers MUST normalize via `getColumnId` / `getColumnAlias` before
|
|
37
|
+
* using as a Map key, joining into strings, or rendering — otherwise
|
|
38
|
+
* objects produce `[object Object]` in serialized output.
|
|
39
|
+
*/
|
|
40
|
+
cols: (string | PatternRef)[];
|
|
33
41
|
at?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
34
42
|
span?: Record<string, number>;
|
|
35
43
|
breakpoints?: {
|
|
@@ -38,6 +46,12 @@ interface ColumnLayout {
|
|
|
38
46
|
}[];
|
|
39
47
|
responsive?: 'viewport' | 'container';
|
|
40
48
|
}
|
|
49
|
+
/** Extract the pattern id string from a column entry. */
|
|
50
|
+
declare function getColumnId(col: string | PatternRef): string;
|
|
51
|
+
/** Extract the alias for a column entry (defaults to pattern id when no `as`). */
|
|
52
|
+
declare function getColumnAlias(col: string | PatternRef): string;
|
|
53
|
+
/** Extract the optional preset for a column entry, or undefined. */
|
|
54
|
+
declare function getColumnPreset(col: string | PatternRef): string | undefined;
|
|
41
55
|
interface StructurePage {
|
|
42
56
|
id: string;
|
|
43
57
|
shell: ShellType;
|
|
@@ -189,8 +203,23 @@ interface BlueprintPage {
|
|
|
189
203
|
patterns?: PatternRef[];
|
|
190
204
|
dna_overrides?: DNAOverrides;
|
|
191
205
|
surface?: string;
|
|
206
|
+
/**
|
|
207
|
+
* Execution-level directives emitted into the page-pack contract.
|
|
208
|
+
* Short imperative rules that cold LLMs should obey when implementing
|
|
209
|
+
* this route. Belongs in the pack (not the narrative doc).
|
|
210
|
+
*/
|
|
211
|
+
directives?: string[];
|
|
192
212
|
}
|
|
193
213
|
type ArchetypeRole = 'primary' | 'gateway' | 'public' | 'auxiliary';
|
|
214
|
+
interface SectionNavigationItem {
|
|
215
|
+
label: string;
|
|
216
|
+
route: string;
|
|
217
|
+
icon?: string;
|
|
218
|
+
hotkey?: string;
|
|
219
|
+
/** Regex or path prefix for "active" matching. Defaults to exact `route` match. */
|
|
220
|
+
active_match?: string;
|
|
221
|
+
badge?: string;
|
|
222
|
+
}
|
|
194
223
|
interface EssenceV31Section {
|
|
195
224
|
id: string;
|
|
196
225
|
role: ArchetypeRole;
|
|
@@ -199,6 +228,14 @@ interface EssenceV31Section {
|
|
|
199
228
|
description: string;
|
|
200
229
|
pages: BlueprintPage[];
|
|
201
230
|
dna_overrides?: DNAOverrides;
|
|
231
|
+
/** Items rendered in the shell's primary navigation for this section. */
|
|
232
|
+
navigation_items?: SectionNavigationItem[];
|
|
233
|
+
/**
|
|
234
|
+
* Execution-level directives emitted into the section-pack contract.
|
|
235
|
+
* Short imperative rules every page in this section must obey.
|
|
236
|
+
* Belongs in the pack (not the narrative doc).
|
|
237
|
+
*/
|
|
238
|
+
directives?: string[];
|
|
202
239
|
}
|
|
203
240
|
interface RouteEntry {
|
|
204
241
|
section: string;
|
|
@@ -217,6 +254,16 @@ interface EssenceV3Guard {
|
|
|
217
254
|
mode: GuardMode;
|
|
218
255
|
dna_enforcement: 'error' | 'warn' | 'off';
|
|
219
256
|
blueprint_enforcement: 'warn' | 'off';
|
|
257
|
+
/**
|
|
258
|
+
* v2.1 C5. Severity for the experiential interactions guard rule (8th
|
|
259
|
+
* rule). When patterns declare `interactions: [...]` but the source
|
|
260
|
+
* tree is missing the canonical implementations, this controls whether
|
|
261
|
+
* the violation is an error, warning, or ignored.
|
|
262
|
+
*
|
|
263
|
+
* Defaults: `creative` mode → 'off'; `guided` → 'warn'; `strict` → 'error'.
|
|
264
|
+
* Authors can override per-essence.
|
|
265
|
+
*/
|
|
266
|
+
interactions_enforcement?: 'error' | 'warn' | 'off';
|
|
220
267
|
}
|
|
221
268
|
interface EssenceMeta {
|
|
222
269
|
archetype: string;
|
|
@@ -233,10 +280,47 @@ interface EssenceMeta {
|
|
|
233
280
|
route?: string;
|
|
234
281
|
action?: string;
|
|
235
282
|
label: string;
|
|
283
|
+
semantics?: HotkeySemantics;
|
|
236
284
|
}>;
|
|
237
|
-
command_palette?: boolean;
|
|
285
|
+
command_palette?: boolean | CommandPaletteContract;
|
|
286
|
+
/** Default hotkey semantics applied to every hotkey unless overridden per-key. */
|
|
287
|
+
hotkey_semantics?: HotkeySemantics;
|
|
238
288
|
};
|
|
239
289
|
}
|
|
290
|
+
interface CommandPaletteContract {
|
|
291
|
+
/** Platform-neutral hotkey (e.g., 'Cmd+K' → Cmd on Mac, Ctrl elsewhere). */
|
|
292
|
+
trigger?: string;
|
|
293
|
+
placeholder?: string;
|
|
294
|
+
/** Preferred width as a CSS length (e.g., '640px' or '40rem'). */
|
|
295
|
+
width?: string;
|
|
296
|
+
/** Presentation mode. */
|
|
297
|
+
styling?: 'modal' | 'sheet' | 'inline' | 'fullscreen';
|
|
298
|
+
/** Seed command vocabulary. If omitted, LLMs may synthesize a minimal default from declared routes. */
|
|
299
|
+
commands?: Array<{
|
|
300
|
+
id: string;
|
|
301
|
+
label: string;
|
|
302
|
+
section?: string;
|
|
303
|
+
hotkey?: string;
|
|
304
|
+
action?: string;
|
|
305
|
+
route?: string;
|
|
306
|
+
}>;
|
|
307
|
+
}
|
|
308
|
+
interface HotkeySemantics {
|
|
309
|
+
/** Max ms between keystrokes in a chord before it resets. Typical: 900. */
|
|
310
|
+
chord_window_ms?: number;
|
|
311
|
+
/** If true (default): hotkeys don't fire while focus is in an editable element. */
|
|
312
|
+
input_guard?: boolean;
|
|
313
|
+
/** If true (default): hotkeys don't fire when a modifier is held unless the key string declares it. */
|
|
314
|
+
modifier_suppression?: boolean;
|
|
315
|
+
/** If true: hotkey matching is case-sensitive. Default false — uppercase implies Shift. */
|
|
316
|
+
match_case?: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* v2.1 C3. If true (default): render the .d-hotkey-indicator corner badge
|
|
319
|
+
* when a chord hotkey prefix is armed. If false: silent chord tracking
|
|
320
|
+
* (no visual feedback). Recommended true for discoverability.
|
|
321
|
+
*/
|
|
322
|
+
show_chord_indicator?: boolean;
|
|
323
|
+
}
|
|
240
324
|
interface EssenceV3 {
|
|
241
325
|
$schema?: string;
|
|
242
326
|
version: '3.0.0' | '3.1.0';
|
|
@@ -252,12 +336,6 @@ declare function flattenPages(blueprint: EssenceBlueprint): BlueprintPage[];
|
|
|
252
336
|
declare function isSectioned(essence: EssenceFile): essence is SectionedEssence;
|
|
253
337
|
declare function isSimple(essence: EssenceFile): essence is Essence;
|
|
254
338
|
|
|
255
|
-
interface ValidationResult {
|
|
256
|
-
valid: boolean;
|
|
257
|
-
errors: string[];
|
|
258
|
-
}
|
|
259
|
-
declare function validateEssence(data: unknown): ValidationResult;
|
|
260
|
-
|
|
261
339
|
interface SpatialHints {
|
|
262
340
|
density_bias?: number;
|
|
263
341
|
content_gap_shift?: number;
|
|
@@ -270,7 +348,15 @@ interface AutoFix {
|
|
|
270
348
|
patch: Record<string, unknown>;
|
|
271
349
|
}
|
|
272
350
|
interface GuardViolation {
|
|
273
|
-
rule: 'theme' | 'structure' | 'layout' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility'
|
|
351
|
+
rule: 'theme' | 'structure' | 'layout' | 'density' | 'theme-mode' | 'pattern-exists' | 'accessibility'
|
|
352
|
+
/**
|
|
353
|
+
* v2.1 C5. Experiential interactions guard rule. Fires when patterns
|
|
354
|
+
* declare `interactions: [...]` but the source tree is missing the
|
|
355
|
+
* canonical implementations. Severity controlled by
|
|
356
|
+
* `meta.guard.interactions_enforcement` (defaults: creative=off,
|
|
357
|
+
* guided=warn, strict=error).
|
|
358
|
+
*/
|
|
359
|
+
| 'interactions';
|
|
274
360
|
severity: 'error' | 'warning';
|
|
275
361
|
message: string;
|
|
276
362
|
suggestion?: string;
|
|
@@ -290,11 +376,20 @@ interface GuardContext {
|
|
|
290
376
|
}>;
|
|
291
377
|
patternRegistry?: Map<string, unknown>;
|
|
292
378
|
a11y_issues?: string[];
|
|
379
|
+
/**
|
|
380
|
+
* v2.1 C5. Pre-computed list of declared interactions whose canonical
|
|
381
|
+
* implementations are missing from the source tree. Produced by
|
|
382
|
+
* `verifyInteractionsInSource` from @decantr/verifier; passed in here
|
|
383
|
+
* so the guard rule can emit violations without owning the source-scan
|
|
384
|
+
* logic. Mirrors the existing `a11y_issues` pattern.
|
|
385
|
+
*
|
|
386
|
+
* Each entry is a short descriptor like
|
|
387
|
+
* `status-pulse (suggestion: Apply 'd-pulse' to the indicator)`.
|
|
388
|
+
*/
|
|
389
|
+
interaction_issues?: string[];
|
|
293
390
|
}
|
|
294
391
|
declare function evaluateGuard(essence: EssenceFile, context?: GuardContext): GuardViolation[];
|
|
295
392
|
|
|
296
|
-
declare function normalizeEssence(input: Record<string, unknown>): EssenceFile;
|
|
297
|
-
|
|
298
393
|
/**
|
|
299
394
|
* Migrate a v2 EssenceFile to v3 format (DNA/Blueprint/Meta split).
|
|
300
395
|
* If already v3, returns unchanged. SectionedEssence uses first section's theme.
|
|
@@ -306,4 +401,12 @@ declare function migrateV2ToV3(essence: EssenceFile): EssenceV3;
|
|
|
306
401
|
*/
|
|
307
402
|
declare function migrateV30ToV31(essence: EssenceV3): EssenceV3;
|
|
308
403
|
|
|
309
|
-
|
|
404
|
+
declare function normalizeEssence(input: Record<string, unknown>): EssenceFile;
|
|
405
|
+
|
|
406
|
+
interface ValidationResult {
|
|
407
|
+
valid: boolean;
|
|
408
|
+
errors: string[];
|
|
409
|
+
}
|
|
410
|
+
declare function validateEssence(data: unknown): ValidationResult;
|
|
411
|
+
|
|
412
|
+
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, getColumnAlias, getColumnId, getColumnPreset, isSectioned, isSimple, isV3, migrateV2ToV3, migrateV30ToV31, normalizeEssence, validateEssence };
|
package/dist/index.js
CHANGED
|
@@ -1,78 +1,3 @@
|
|
|
1
|
-
// src/types.ts
|
|
2
|
-
function isV3(essence) {
|
|
3
|
-
return (essence.version === "3.0.0" || essence.version === "3.1.0") && "dna" in essence && "blueprint" in essence;
|
|
4
|
-
}
|
|
5
|
-
function flattenPages(blueprint) {
|
|
6
|
-
if (blueprint.sections && blueprint.sections.length > 0) {
|
|
7
|
-
return blueprint.sections.flatMap(
|
|
8
|
-
(s) => s.pages.map((p) => ({
|
|
9
|
-
...p,
|
|
10
|
-
shell_override: p.shell_override ?? (s.shell !== blueprint.shell ? s.shell : void 0)
|
|
11
|
-
}))
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
return blueprint.pages ?? [];
|
|
15
|
-
}
|
|
16
|
-
function isSectioned(essence) {
|
|
17
|
-
if (isV3(essence)) return false;
|
|
18
|
-
return "sections" in essence && Array.isArray(essence.sections);
|
|
19
|
-
}
|
|
20
|
-
function isSimple(essence) {
|
|
21
|
-
if (isV3(essence)) return false;
|
|
22
|
-
return "archetype" in essence && !("sections" in essence);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// src/validate.ts
|
|
26
|
-
import Ajv from "ajv";
|
|
27
|
-
import { readFileSync, existsSync } from "fs";
|
|
28
|
-
import { fileURLToPath } from "url";
|
|
29
|
-
import { dirname, join } from "path";
|
|
30
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
-
var v2SchemaPath = join(__dirname, "..", "schema", "essence.v2.json");
|
|
32
|
-
var v3SchemaPath = join(__dirname, "..", "schema", "essence.v3.json");
|
|
33
|
-
var cachedAjv = null;
|
|
34
|
-
var validatorCache = /* @__PURE__ */ new Map();
|
|
35
|
-
function getAjv() {
|
|
36
|
-
if (!cachedAjv) {
|
|
37
|
-
cachedAjv = new Ajv({ allErrors: true, strict: false, validateSchema: false });
|
|
38
|
-
}
|
|
39
|
-
return cachedAjv;
|
|
40
|
-
}
|
|
41
|
-
function getValidator(version) {
|
|
42
|
-
if (validatorCache.has(version)) return validatorCache.get(version);
|
|
43
|
-
const schemaPath = version === "v3" ? v3SchemaPath : v2SchemaPath;
|
|
44
|
-
if (!existsSync(schemaPath)) return null;
|
|
45
|
-
const schema = JSON.parse(readFileSync(schemaPath, "utf-8"));
|
|
46
|
-
const ajv = getAjv();
|
|
47
|
-
const validate = ajv.compile(schema);
|
|
48
|
-
validatorCache.set(version, validate);
|
|
49
|
-
return validate;
|
|
50
|
-
}
|
|
51
|
-
function detectVersion(data) {
|
|
52
|
-
if (typeof data === "object" && data !== null && "version" in data) {
|
|
53
|
-
const v = data.version;
|
|
54
|
-
if (v === "3.0.0" || v === "3.1.0") return "v3";
|
|
55
|
-
}
|
|
56
|
-
return "v2";
|
|
57
|
-
}
|
|
58
|
-
function validateEssence(data) {
|
|
59
|
-
const version = detectVersion(data);
|
|
60
|
-
const validate = getValidator(version);
|
|
61
|
-
if (!validate) {
|
|
62
|
-
return { valid: false, errors: [`No schema available for ${version} documents`] };
|
|
63
|
-
}
|
|
64
|
-
const valid = validate(data);
|
|
65
|
-
if (valid) {
|
|
66
|
-
return { valid: true, errors: [] };
|
|
67
|
-
}
|
|
68
|
-
const errors = (validate.errors ?? []).map((err) => {
|
|
69
|
-
const path = err.instancePath || "/";
|
|
70
|
-
const msg = err.message ?? "unknown error";
|
|
71
|
-
return `${path}: ${msg}`;
|
|
72
|
-
});
|
|
73
|
-
return { valid: false, errors };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
1
|
// src/density.ts
|
|
77
2
|
var RULES = [
|
|
78
3
|
{ traits: ["tactical", "dense", "data-dense", "utilitarian"], level: "compact", gap: 3 },
|
|
@@ -175,6 +100,41 @@ function computeSpatialTokens(density, spatialHints) {
|
|
|
175
100
|
return result;
|
|
176
101
|
}
|
|
177
102
|
|
|
103
|
+
// src/types.ts
|
|
104
|
+
function getColumnId(col) {
|
|
105
|
+
return typeof col === "string" ? col : col.pattern;
|
|
106
|
+
}
|
|
107
|
+
function getColumnAlias(col) {
|
|
108
|
+
if (typeof col === "string") return col;
|
|
109
|
+
return col.as ?? col.pattern;
|
|
110
|
+
}
|
|
111
|
+
function getColumnPreset(col) {
|
|
112
|
+
if (typeof col === "string") return void 0;
|
|
113
|
+
return col.preset;
|
|
114
|
+
}
|
|
115
|
+
function isV3(essence) {
|
|
116
|
+
return (essence.version === "3.0.0" || essence.version === "3.1.0") && "dna" in essence && "blueprint" in essence;
|
|
117
|
+
}
|
|
118
|
+
function flattenPages(blueprint) {
|
|
119
|
+
if (blueprint.sections && blueprint.sections.length > 0) {
|
|
120
|
+
return blueprint.sections.flatMap(
|
|
121
|
+
(s) => s.pages.map((p) => ({
|
|
122
|
+
...p,
|
|
123
|
+
shell_override: p.shell_override ?? (s.shell !== blueprint.shell ? s.shell : void 0)
|
|
124
|
+
}))
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return blueprint.pages ?? [];
|
|
128
|
+
}
|
|
129
|
+
function isSectioned(essence) {
|
|
130
|
+
if (isV3(essence)) return false;
|
|
131
|
+
return "sections" in essence && Array.isArray(essence.sections);
|
|
132
|
+
}
|
|
133
|
+
function isSimple(essence) {
|
|
134
|
+
if (isV3(essence)) return false;
|
|
135
|
+
return "archetype" in essence && !("sections" in essence);
|
|
136
|
+
}
|
|
137
|
+
|
|
178
138
|
// src/guard.ts
|
|
179
139
|
function checkThemeModeCompatibility(essence, context) {
|
|
180
140
|
if (!context.themeRegistry) return null;
|
|
@@ -218,6 +178,8 @@ function collectPatternIds(item, ids) {
|
|
|
218
178
|
for (const col of item.cols) {
|
|
219
179
|
if (typeof col === "string") {
|
|
220
180
|
ids.add(col);
|
|
181
|
+
} else if (col && typeof col === "object" && "pattern" in col && typeof col.pattern === "string") {
|
|
182
|
+
ids.add(col.pattern);
|
|
221
183
|
}
|
|
222
184
|
}
|
|
223
185
|
}
|
|
@@ -277,6 +239,34 @@ function checkAccessibility(essence, context) {
|
|
|
277
239
|
}
|
|
278
240
|
return null;
|
|
279
241
|
}
|
|
242
|
+
function checkInteractions(essence, context) {
|
|
243
|
+
if (!context.interaction_issues || context.interaction_issues.length === 0) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const guard = isV3(essence) ? essence.meta.guard : null;
|
|
247
|
+
if (!guard) return null;
|
|
248
|
+
let enforcement;
|
|
249
|
+
if (guard.interactions_enforcement) {
|
|
250
|
+
enforcement = guard.interactions_enforcement;
|
|
251
|
+
} else if (guard.mode === "strict") {
|
|
252
|
+
enforcement = "error";
|
|
253
|
+
} else if (guard.mode === "guided") {
|
|
254
|
+
enforcement = "warn";
|
|
255
|
+
} else {
|
|
256
|
+
enforcement = "off";
|
|
257
|
+
}
|
|
258
|
+
if (enforcement === "off") return null;
|
|
259
|
+
const issueList = context.interaction_issues.slice(0, 3).join("; ");
|
|
260
|
+
const moreCount = context.interaction_issues.length > 3 ? ` (+${context.interaction_issues.length - 3} more)` : "";
|
|
261
|
+
return {
|
|
262
|
+
rule: "interactions",
|
|
263
|
+
severity: enforcement === "error" ? "error" : "warning",
|
|
264
|
+
message: `Declared pattern interactions are not implemented in source: ${issueList}${moreCount}`,
|
|
265
|
+
suggestion: 'See "Interaction Requirements" in DECANTR.md for canonical implementations. Each declared interaction maps to a treatment class or handler pattern.',
|
|
266
|
+
layer: "blueprint",
|
|
267
|
+
autoFixable: false
|
|
268
|
+
};
|
|
269
|
+
}
|
|
280
270
|
function evaluateGuard(essence, context = {}) {
|
|
281
271
|
const guard = isV3(essence) ? essence.meta.guard : essence.guard;
|
|
282
272
|
if (guard.mode === "creative") {
|
|
@@ -335,7 +325,10 @@ function evaluateGuard(essence, context = {}) {
|
|
|
335
325
|
...isV3(essence) ? {
|
|
336
326
|
layer: "blueprint",
|
|
337
327
|
autoFixable: true,
|
|
338
|
-
autoFix: {
|
|
328
|
+
autoFix: {
|
|
329
|
+
type: "update_layout",
|
|
330
|
+
patch: { page: context.pageId, layout: context.layout }
|
|
331
|
+
}
|
|
339
332
|
} : {}
|
|
340
333
|
});
|
|
341
334
|
}
|
|
@@ -368,6 +361,10 @@ function evaluateGuard(essence, context = {}) {
|
|
|
368
361
|
if (accessibilityViolation) {
|
|
369
362
|
violations.push(accessibilityViolation);
|
|
370
363
|
}
|
|
364
|
+
const interactionsViolation = checkInteractions(essence, context);
|
|
365
|
+
if (interactionsViolation) {
|
|
366
|
+
violations.push(interactionsViolation);
|
|
367
|
+
}
|
|
371
368
|
if (isV3(essence)) {
|
|
372
369
|
const v3Guard = guard;
|
|
373
370
|
if (v3Guard.dna_enforcement === "off") {
|
|
@@ -413,109 +410,6 @@ function getPageDensityOverride(essence, pageId) {
|
|
|
413
410
|
return densityGapMap[page.dna_overrides.density] ?? void 0;
|
|
414
411
|
}
|
|
415
412
|
|
|
416
|
-
// src/normalize.ts
|
|
417
|
-
function normalizeEssence(input) {
|
|
418
|
-
if (input.version === "3.0.0" || input.version === "3.1.0") {
|
|
419
|
-
return input;
|
|
420
|
-
}
|
|
421
|
-
if (input.theme && input.platform) {
|
|
422
|
-
return input;
|
|
423
|
-
}
|
|
424
|
-
if (input.sections) {
|
|
425
|
-
return normalizeSectioned(input);
|
|
426
|
-
}
|
|
427
|
-
return normalizeSimple(input);
|
|
428
|
-
}
|
|
429
|
-
function normalizeSimple(v1) {
|
|
430
|
-
const vintage = v1.vintage;
|
|
431
|
-
const vessel = v1.vessel;
|
|
432
|
-
const clarity = v1.clarity;
|
|
433
|
-
const cork = v1.cork;
|
|
434
|
-
const structure = v1.structure;
|
|
435
|
-
return {
|
|
436
|
-
version: "2.0.0",
|
|
437
|
-
archetype: v1.terroir ?? v1.vignette ?? v1.archetype,
|
|
438
|
-
theme: {
|
|
439
|
-
id: vintage?.style ?? "",
|
|
440
|
-
mode: vintage?.mode ?? "dark",
|
|
441
|
-
...vintage?.shape ? { shape: vintage.shape } : {}
|
|
442
|
-
},
|
|
443
|
-
// Accept both old 'character' and new 'personality' field names
|
|
444
|
-
personality: v1.character ?? v1.personality,
|
|
445
|
-
platform: {
|
|
446
|
-
type: vessel?.type ?? "spa",
|
|
447
|
-
routing: vessel?.routing ?? "hash"
|
|
448
|
-
},
|
|
449
|
-
structure: (structure ?? []).map(normalizeStructurePage),
|
|
450
|
-
features: v1.tannins ?? v1.features ?? [],
|
|
451
|
-
density: {
|
|
452
|
-
level: clarity?.density ?? "comfortable",
|
|
453
|
-
content_gap: stripGapPrefix(clarity?.content_gap ?? "4")
|
|
454
|
-
},
|
|
455
|
-
guard: normalizeGuard(cork),
|
|
456
|
-
target: v1.target ?? "decantr",
|
|
457
|
-
...v1._impression ? { _impression: v1._impression } : {}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
function normalizeSectioned(v1) {
|
|
461
|
-
const vessel = v1.vessel;
|
|
462
|
-
const clarity = v1.clarity;
|
|
463
|
-
const cork = v1.cork;
|
|
464
|
-
const sections = v1.sections;
|
|
465
|
-
return {
|
|
466
|
-
version: "2.0.0",
|
|
467
|
-
platform: {
|
|
468
|
-
type: vessel?.type ?? "spa",
|
|
469
|
-
routing: vessel?.routing ?? "hash"
|
|
470
|
-
},
|
|
471
|
-
// Accept both old 'character' and new 'personality' field names
|
|
472
|
-
personality: v1.character ?? v1.personality,
|
|
473
|
-
sections: sections.map((section) => ({
|
|
474
|
-
id: section.id,
|
|
475
|
-
path: section.path,
|
|
476
|
-
archetype: section.terroir ?? section.vignette ?? section.archetype,
|
|
477
|
-
theme: {
|
|
478
|
-
id: section.vintage?.style ?? "",
|
|
479
|
-
mode: section.vintage?.mode ?? "dark"
|
|
480
|
-
},
|
|
481
|
-
structure: (section.structure ?? []).map(normalizeStructurePage),
|
|
482
|
-
...section.tannins ? { features: section.tannins } : {}
|
|
483
|
-
})),
|
|
484
|
-
...v1.shared_tannins ? { shared_features: v1.shared_tannins } : {},
|
|
485
|
-
density: {
|
|
486
|
-
level: clarity?.density ?? "comfortable",
|
|
487
|
-
content_gap: stripGapPrefix(clarity?.content_gap ?? "4")
|
|
488
|
-
},
|
|
489
|
-
guard: normalizeGuard(cork),
|
|
490
|
-
target: v1.target ?? "decantr"
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
function normalizeStructurePage(page) {
|
|
494
|
-
return {
|
|
495
|
-
id: page.id,
|
|
496
|
-
shell: page.carafe ?? page.shell,
|
|
497
|
-
layout: page.blend ?? page.layout,
|
|
498
|
-
...page.surface ? { surface: page.surface } : {}
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
function normalizeGuard(cork) {
|
|
502
|
-
if (!cork) return { mode: "creative" };
|
|
503
|
-
const modeMap = {
|
|
504
|
-
creative: "creative",
|
|
505
|
-
maintenance: "strict",
|
|
506
|
-
strict: "strict",
|
|
507
|
-
guided: "guided"
|
|
508
|
-
};
|
|
509
|
-
return {
|
|
510
|
-
...cork.enforce_style !== void 0 ? { enforce_style: cork.enforce_style } : {},
|
|
511
|
-
mode: modeMap[cork.mode ?? "creative"] ?? "creative"
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
function stripGapPrefix(gap) {
|
|
515
|
-
const match = gap.match(/^_gap(\d+)$/);
|
|
516
|
-
return match ? match[1] : gap;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
413
|
// src/migrate.ts
|
|
520
414
|
function migrateV2ToV3(essence) {
|
|
521
415
|
if (isV3(essence)) return essence;
|
|
@@ -693,11 +587,172 @@ function migrateV30ToV31(essence) {
|
|
|
693
587
|
}
|
|
694
588
|
};
|
|
695
589
|
}
|
|
590
|
+
|
|
591
|
+
// src/normalize.ts
|
|
592
|
+
function normalizeEssence(input) {
|
|
593
|
+
if (input.version === "3.0.0" || input.version === "3.1.0") {
|
|
594
|
+
return input;
|
|
595
|
+
}
|
|
596
|
+
if (input.theme && input.platform) {
|
|
597
|
+
return input;
|
|
598
|
+
}
|
|
599
|
+
if (input.sections) {
|
|
600
|
+
return normalizeSectioned(input);
|
|
601
|
+
}
|
|
602
|
+
return normalizeSimple(input);
|
|
603
|
+
}
|
|
604
|
+
function normalizeSimple(v1) {
|
|
605
|
+
const vintage = v1.vintage;
|
|
606
|
+
const vessel = v1.vessel;
|
|
607
|
+
const clarity = v1.clarity;
|
|
608
|
+
const cork = v1.cork;
|
|
609
|
+
const structure = v1.structure;
|
|
610
|
+
return {
|
|
611
|
+
version: "2.0.0",
|
|
612
|
+
archetype: v1.terroir ?? v1.vignette ?? v1.archetype,
|
|
613
|
+
theme: {
|
|
614
|
+
id: vintage?.style ?? "",
|
|
615
|
+
mode: vintage?.mode ?? "dark",
|
|
616
|
+
...vintage?.shape ? { shape: vintage.shape } : {}
|
|
617
|
+
},
|
|
618
|
+
// Accept both old 'character' and new 'personality' field names
|
|
619
|
+
personality: v1.character ?? v1.personality,
|
|
620
|
+
platform: {
|
|
621
|
+
type: vessel?.type ?? "spa",
|
|
622
|
+
// Modern-SPA default. See packages/cli/src/scaffold.ts getPlatformMeta for rationale.
|
|
623
|
+
routing: vessel?.routing ?? "history"
|
|
624
|
+
},
|
|
625
|
+
structure: (structure ?? []).map(normalizeStructurePage),
|
|
626
|
+
features: v1.tannins ?? v1.features ?? [],
|
|
627
|
+
density: {
|
|
628
|
+
level: clarity?.density ?? "comfortable",
|
|
629
|
+
content_gap: stripGapPrefix(clarity?.content_gap ?? "4")
|
|
630
|
+
},
|
|
631
|
+
guard: normalizeGuard(cork),
|
|
632
|
+
target: v1.target ?? "decantr",
|
|
633
|
+
...v1._impression ? { _impression: v1._impression } : {}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function normalizeSectioned(v1) {
|
|
637
|
+
const vessel = v1.vessel;
|
|
638
|
+
const clarity = v1.clarity;
|
|
639
|
+
const cork = v1.cork;
|
|
640
|
+
const sections = v1.sections;
|
|
641
|
+
return {
|
|
642
|
+
version: "2.0.0",
|
|
643
|
+
platform: {
|
|
644
|
+
type: vessel?.type ?? "spa",
|
|
645
|
+
// Modern-SPA default. See packages/cli/src/scaffold.ts getPlatformMeta for rationale.
|
|
646
|
+
routing: vessel?.routing ?? "history"
|
|
647
|
+
},
|
|
648
|
+
// Accept both old 'character' and new 'personality' field names
|
|
649
|
+
personality: v1.character ?? v1.personality,
|
|
650
|
+
sections: sections.map((section) => ({
|
|
651
|
+
id: section.id,
|
|
652
|
+
path: section.path,
|
|
653
|
+
archetype: section.terroir ?? section.vignette ?? section.archetype,
|
|
654
|
+
theme: {
|
|
655
|
+
id: section.vintage?.style ?? "",
|
|
656
|
+
mode: section.vintage?.mode ?? "dark"
|
|
657
|
+
},
|
|
658
|
+
structure: (section.structure ?? []).map(
|
|
659
|
+
normalizeStructurePage
|
|
660
|
+
),
|
|
661
|
+
...section.tannins ? { features: section.tannins } : {}
|
|
662
|
+
})),
|
|
663
|
+
...v1.shared_tannins ? { shared_features: v1.shared_tannins } : {},
|
|
664
|
+
density: {
|
|
665
|
+
level: clarity?.density ?? "comfortable",
|
|
666
|
+
content_gap: stripGapPrefix(clarity?.content_gap ?? "4")
|
|
667
|
+
},
|
|
668
|
+
guard: normalizeGuard(cork),
|
|
669
|
+
target: v1.target ?? "decantr"
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function normalizeStructurePage(page) {
|
|
673
|
+
return {
|
|
674
|
+
id: page.id,
|
|
675
|
+
shell: page.carafe ?? page.shell,
|
|
676
|
+
layout: page.blend ?? page.layout,
|
|
677
|
+
...page.surface ? { surface: page.surface } : {}
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function normalizeGuard(cork) {
|
|
681
|
+
if (!cork) return { mode: "creative" };
|
|
682
|
+
const modeMap = {
|
|
683
|
+
creative: "creative",
|
|
684
|
+
maintenance: "strict",
|
|
685
|
+
strict: "strict",
|
|
686
|
+
guided: "guided"
|
|
687
|
+
};
|
|
688
|
+
return {
|
|
689
|
+
...cork.enforce_style !== void 0 ? { enforce_style: cork.enforce_style } : {},
|
|
690
|
+
mode: modeMap[cork.mode ?? "creative"] ?? "creative"
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function stripGapPrefix(gap) {
|
|
694
|
+
const match = gap.match(/^_gap(\d+)$/);
|
|
695
|
+
return match ? match[1] : gap;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/validate.ts
|
|
699
|
+
import { existsSync, readFileSync } from "fs";
|
|
700
|
+
import { dirname, join } from "path";
|
|
701
|
+
import { fileURLToPath } from "url";
|
|
702
|
+
import Ajv from "ajv";
|
|
703
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
704
|
+
var v2SchemaPath = join(__dirname, "..", "schema", "essence.v2.json");
|
|
705
|
+
var v3SchemaPath = join(__dirname, "..", "schema", "essence.v3.json");
|
|
706
|
+
var cachedAjv = null;
|
|
707
|
+
var validatorCache = /* @__PURE__ */ new Map();
|
|
708
|
+
function getAjv() {
|
|
709
|
+
if (!cachedAjv) {
|
|
710
|
+
cachedAjv = new Ajv({ allErrors: true, strict: false, validateSchema: false });
|
|
711
|
+
}
|
|
712
|
+
return cachedAjv;
|
|
713
|
+
}
|
|
714
|
+
function getValidator(version) {
|
|
715
|
+
if (validatorCache.has(version)) return validatorCache.get(version);
|
|
716
|
+
const schemaPath = version === "v3" ? v3SchemaPath : v2SchemaPath;
|
|
717
|
+
if (!existsSync(schemaPath)) return null;
|
|
718
|
+
const schema = JSON.parse(readFileSync(schemaPath, "utf-8"));
|
|
719
|
+
const ajv = getAjv();
|
|
720
|
+
const validate = ajv.compile(schema);
|
|
721
|
+
validatorCache.set(version, validate);
|
|
722
|
+
return validate;
|
|
723
|
+
}
|
|
724
|
+
function detectVersion(data) {
|
|
725
|
+
if (typeof data === "object" && data !== null && "version" in data) {
|
|
726
|
+
const v = data.version;
|
|
727
|
+
if (v === "3.0.0" || v === "3.1.0") return "v3";
|
|
728
|
+
}
|
|
729
|
+
return "v2";
|
|
730
|
+
}
|
|
731
|
+
function validateEssence(data) {
|
|
732
|
+
const version = detectVersion(data);
|
|
733
|
+
const validate = getValidator(version);
|
|
734
|
+
if (!validate) {
|
|
735
|
+
return { valid: false, errors: [`No schema available for ${version} documents`] };
|
|
736
|
+
}
|
|
737
|
+
const valid = validate(data);
|
|
738
|
+
if (valid) {
|
|
739
|
+
return { valid: true, errors: [] };
|
|
740
|
+
}
|
|
741
|
+
const errors = (validate.errors ?? []).map((err) => {
|
|
742
|
+
const path = err.instancePath || "/";
|
|
743
|
+
const msg = err.message ?? "unknown error";
|
|
744
|
+
return `${path}: ${msg}`;
|
|
745
|
+
});
|
|
746
|
+
return { valid: false, errors };
|
|
747
|
+
}
|
|
696
748
|
export {
|
|
697
749
|
computeDensity,
|
|
698
750
|
computeSpatialTokens,
|
|
699
751
|
evaluateGuard,
|
|
700
752
|
flattenPages,
|
|
753
|
+
getColumnAlias,
|
|
754
|
+
getColumnId,
|
|
755
|
+
getColumnPreset,
|
|
701
756
|
isSectioned,
|
|
702
757
|
isSimple,
|
|
703
758
|
isV3,
|
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 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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/density.ts","../src/types.ts","../src/guard.ts","../src/migrate.ts","../src/normalize.ts","../src/validate.ts"],"sourcesContent":["import type { Density, DensityLevel, SpatialTokenHints, SpatialTokens } 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(personality: string[], spatialHints?: SpatialHints): 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","/**\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 /**\n * Column entries. Each entry is either a pattern id string OR a\n * PatternRef object with `pattern`, optional `preset`, and optional\n * `as` alias. Mixing the two forms is permitted by the schema.\n * Consumers MUST normalize via `getColumnId` / `getColumnAlias` before\n * using as a Map key, joining into strings, or rendering — otherwise\n * objects produce `[object Object]` in serialized output.\n */\n cols: (string | PatternRef)[];\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\n/** Extract the pattern id string from a column entry. */\nexport function getColumnId(col: string | PatternRef): string {\n return typeof col === 'string' ? col : col.pattern;\n}\n\n/** Extract the alias for a column entry (defaults to pattern id when no `as`). */\nexport function getColumnAlias(col: string | PatternRef): string {\n if (typeof col === 'string') return col;\n return col.as ?? col.pattern;\n}\n\n/** Extract the optional preset for a column entry, or undefined. */\nexport function getColumnPreset(col: string | PatternRef): string | undefined {\n if (typeof col === 'string') return undefined;\n return col.preset;\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 * Execution-level directives emitted into the page-pack contract.\n * Short imperative rules that cold LLMs should obey when implementing\n * this route. Belongs in the pack (not the narrative doc).\n */\n directives?: string[];\n}\n\nexport type ArchetypeRole = 'primary' | 'gateway' | 'public' | 'auxiliary';\n\nexport interface SectionNavigationItem {\n label: string;\n route: string;\n icon?: string;\n hotkey?: string;\n /** Regex or path prefix for \"active\" matching. Defaults to exact `route` match. */\n active_match?: string;\n badge?: string;\n}\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 /** Items rendered in the shell's primary navigation for this section. */\n navigation_items?: SectionNavigationItem[];\n /**\n * Execution-level directives emitted into the section-pack contract.\n * Short imperative rules every page in this section must obey.\n * Belongs in the pack (not the narrative doc).\n */\n directives?: string[];\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 * v2.1 C5. Severity for the experiential interactions guard rule (8th\n * rule). When patterns declare `interactions: [...]` but the source\n * tree is missing the canonical implementations, this controls whether\n * the violation is an error, warning, or ignored.\n *\n * Defaults: `creative` mode → 'off'; `guided` → 'warn'; `strict` → 'error'.\n * Authors can override per-essence.\n */\n interactions_enforcement?: 'error' | '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<{\n key: string;\n route?: string;\n action?: string;\n label: string;\n semantics?: HotkeySemantics;\n }>;\n command_palette?: boolean | CommandPaletteContract;\n /** Default hotkey semantics applied to every hotkey unless overridden per-key. */\n hotkey_semantics?: HotkeySemantics;\n };\n}\n\nexport interface CommandPaletteContract {\n /** Platform-neutral hotkey (e.g., 'Cmd+K' → Cmd on Mac, Ctrl elsewhere). */\n trigger?: string;\n placeholder?: string;\n /** Preferred width as a CSS length (e.g., '640px' or '40rem'). */\n width?: string;\n /** Presentation mode. */\n styling?: 'modal' | 'sheet' | 'inline' | 'fullscreen';\n /** Seed command vocabulary. If omitted, LLMs may synthesize a minimal default from declared routes. */\n commands?: Array<{\n id: string;\n label: string;\n section?: string;\n hotkey?: string;\n action?: string;\n route?: string;\n }>;\n}\n\nexport interface HotkeySemantics {\n /** Max ms between keystrokes in a chord before it resets. Typical: 900. */\n chord_window_ms?: number;\n /** If true (default): hotkeys don't fire while focus is in an editable element. */\n input_guard?: boolean;\n /** If true (default): hotkeys don't fire when a modifier is held unless the key string declares it. */\n modifier_suppression?: boolean;\n /** If true: hotkey matching is case-sensitive. Default false — uppercase implies Shift. */\n match_case?: boolean;\n /**\n * v2.1 C3. If true (default): render the .d-hotkey-indicator corner badge\n * when a chord hotkey prefix is armed. If false: silent chord tracking\n * (no visual feedback). Recommended true for discoverability.\n */\n show_chord_indicator?: boolean;\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 (\n (essence.version === '3.0.0' || essence.version === '3.1.0') &&\n 'dna' in essence &&\n 'blueprint' in essence\n );\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:\n 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 type {\n DensityLevel,\n EssenceFile,\n EssenceV3,\n EssenceV3Guard,\n LayoutItem,\n StructurePage,\n} from './types.js';\nimport { flattenPages, isSectioned, isSimple, isV3 } 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:\n | 'theme'\n | 'structure'\n | 'layout'\n | 'density'\n | 'theme-mode'\n | 'pattern-exists'\n | 'accessibility'\n /**\n * v2.1 C5. Experiential interactions guard rule. Fires when patterns\n * declare `interactions: [...]` but the source tree is missing the\n * canonical implementations. Severity controlled by\n * `meta.guard.interactions_enforcement` (defaults: creative=off,\n * guided=warn, strict=error).\n */\n | 'interactions';\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 * v2.1 C5. Pre-computed list of declared interactions whose canonical\n * implementations are missing from the source tree. Produced by\n * `verifyInteractionsInSource` from @decantr/verifier; passed in here\n * so the guard rule can emit violations without owning the source-scan\n * logic. Mirrors the existing `a11y_issues` pattern.\n *\n * Each entry is a short descriptor like\n * `status-pulse (suggestion: Apply 'd-pulse' to the indicator)`.\n */\n interaction_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 =\n 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 * Handles cols entries that are either string ids OR PatternRef objects\n * (the schema permits mixing). Without the object branch, PatternRef cols\n * silently dropped from the registry-existence check, masking missing\n * patterns.\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 if (typeof col === 'string') {\n ids.add(col);\n } else if (\n col &&\n typeof col === 'object' &&\n 'pattern' in col &&\n typeof (col as { pattern: unknown }).pattern === 'string'\n ) {\n ids.add((col as { pattern: string }).pattern);\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(essence: EssenceFile, context: GuardContext): 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 =\n 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(essence: EssenceFile, context: GuardContext): GuardViolation | null {\n const accessibility = isV3(essence)\n ? essence.dna.accessibility\n : 'accessibility' in essence\n ? essence.accessibility\n : 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 =\n 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:\n '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\n/**\n * v2.1 C5. Experiential interactions guard rule (8th rule). Patterns\n * declare runtime interactions in pattern.v2.json (e.g., status-pulse,\n * drag-nodes, hover-tooltip). When the source tree doesn't implement\n * those interactions, this rule emits a violation. Source scanning\n * happens in @decantr/verifier; pre-computed results land here as\n * `context.interaction_issues`.\n *\n * Severity is governed by `meta.guard.interactions_enforcement`:\n * - 'error' → emits as error (build fails)\n * - 'warn' → emits as warning (build passes, surfaces in CLI)\n * - 'off' → suppresses entirely\n *\n * Defaults when the field is omitted, derived from guard.mode:\n * - creative → 'off'\n * - guided → 'warn'\n * - strict → 'error'\n */\nfunction checkInteractions(essence: EssenceFile, context: GuardContext): GuardViolation | null {\n if (!context.interaction_issues || context.interaction_issues.length === 0) {\n return null;\n }\n\n const guard = isV3(essence) ? essence.meta.guard : null;\n if (!guard) return null; // v2 essences don't carry the field — skip silently.\n\n // Resolve enforcement: explicit field wins, otherwise mode-derived default.\n let enforcement: 'error' | 'warn' | 'off';\n if (guard.interactions_enforcement) {\n enforcement = guard.interactions_enforcement;\n } else if (guard.mode === 'strict') {\n enforcement = 'error';\n } else if (guard.mode === 'guided') {\n enforcement = 'warn';\n } else {\n enforcement = 'off';\n }\n\n if (enforcement === 'off') return null;\n\n const issueList = context.interaction_issues.slice(0, 3).join('; ');\n const moreCount =\n context.interaction_issues.length > 3\n ? ` (+${context.interaction_issues.length - 3} more)`\n : '';\n\n return {\n rule: 'interactions',\n severity: enforcement === 'error' ? 'error' : 'warning',\n message: `Declared pattern interactions are not implemented in source: ${issueList}${moreCount}`,\n suggestion:\n 'See \"Interaction Requirements\" in DECANTR.md for canonical implementations. Each declared interaction maps to a treatment class or handler pattern.',\n layer: 'blueprint' as const,\n autoFixable: false,\n };\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)\n ? true\n : (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 ? {\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\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 =\n 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 ? {\n layer: 'blueprint' as const,\n autoFixable: true,\n autoFix: {\n type: 'update_layout' as const,\n patch: { page: context.pageId, layout: context.layout },\n },\n }\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 // Rule 9: Experiential interactions (v2.1 C5). Only fires when caller\n // pre-computed `interaction_issues` from the source-tree scan; severity\n // governed by `meta.guard.interactions_enforcement` with mode-derived\n // defaults. See checkInteractions for the full resolution table.\n const interactionsViolation = checkInteractions(essence, context);\n if (interactionsViolation) {\n violations.push(interactionsViolation);\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 {\n DensityLevel,\n Essence,\n EssenceBlueprint,\n EssenceDNA,\n EssenceFile,\n EssenceMeta,\n EssenceV3,\n EssenceV31Section,\n GuardMode,\n SectionedEssence,\n ThemeShape,\n} from './types.js';\nimport { isSectioned, isSimple, 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':\n return 12;\n case 'rounded':\n return 8;\n case 'sharp':\n return 2;\n default:\n 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","import type {\n Essence,\n EssenceFile,\n EssenceV3,\n GuardMode,\n SectionedEssence,\n StructurePage,\n} 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 // Modern-SPA default. See packages/cli/src/scaffold.ts getPlatformMeta for rationale.\n routing: (vessel?.routing ?? 'history') 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 // Modern-SPA default. See packages/cli/src/scaffold.ts getPlatformMeta for rationale.\n routing: (vessel?.routing ?? 'history') 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\n | 'light'\n | 'dark'\n | 'auto',\n },\n structure: ((section.structure as Array<Record<string, unknown>>) ?? []).map(\n normalizeStructurePage,\n ),\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 { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport Ajv from 'ajv';\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"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decantr/essence-spec",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Essence schemas, validation, migration, and TypeScript types for Decantr",
|
|
5
5
|
"author": "Decantr AI",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
"dist",
|
|
32
32
|
"schema"
|
|
33
33
|
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
34
37
|
"publishConfig": {
|
|
35
38
|
"access": "public"
|
|
36
39
|
},
|
|
@@ -40,6 +43,7 @@
|
|
|
40
43
|
"scripts": {
|
|
41
44
|
"build": "tsup",
|
|
42
45
|
"test": "vitest run",
|
|
43
|
-
"test:watch": "vitest"
|
|
46
|
+
"test:watch": "vitest",
|
|
47
|
+
"preversion": "pnpm build && pnpm test"
|
|
44
48
|
}
|
|
45
49
|
}
|
package/schema/essence.v3.json
CHANGED
|
@@ -156,6 +156,11 @@
|
|
|
156
156
|
"route": { "type": "string", "minLength": 1 },
|
|
157
157
|
"shell_override": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
|
|
158
158
|
"layout": { "type": "array", "items": { "$ref": "#/$defs/LayoutItem" }, "minItems": 1 },
|
|
159
|
+
"default_layout": {
|
|
160
|
+
"type": "array",
|
|
161
|
+
"items": { "$ref": "#/$defs/LayoutItem" },
|
|
162
|
+
"description": "Legacy / archetype-derived layout field. Carries through from archetype.pages[].default_layout and is retained on the essence for traceability. Runtime uses `layout` as the effective composition."
|
|
163
|
+
},
|
|
159
164
|
"dna_overrides": { "$ref": "#/$defs/DNAOverrides" },
|
|
160
165
|
"surface": { "type": "string" },
|
|
161
166
|
"directives": {
|
|
@@ -257,7 +262,16 @@
|
|
|
257
262
|
"required": ["cols"],
|
|
258
263
|
"additionalProperties": false,
|
|
259
264
|
"properties": {
|
|
260
|
-
"cols": {
|
|
265
|
+
"cols": {
|
|
266
|
+
"type": "array",
|
|
267
|
+
"items": {
|
|
268
|
+
"oneOf": [
|
|
269
|
+
{ "type": "string", "minLength": 1 },
|
|
270
|
+
{ "$ref": "#/$defs/PatternRef" }
|
|
271
|
+
]
|
|
272
|
+
},
|
|
273
|
+
"minItems": 2
|
|
274
|
+
},
|
|
261
275
|
"at": { "type": "string", "enum": ["sm", "md", "lg", "xl", "2xl"] },
|
|
262
276
|
"span": { "type": "object", "additionalProperties": { "type": "number", "minimum": 1 } },
|
|
263
277
|
"breakpoints": { "type": "array", "items": { "type": "object", "required": ["at", "cols"], "properties": { "at": { "type": "string" }, "cols": { "type": "number" } } } },
|
|
@@ -293,7 +307,12 @@
|
|
|
293
307
|
"properties": {
|
|
294
308
|
"mode": { "type": "string", "enum": ["creative", "guided", "strict"] },
|
|
295
309
|
"dna_enforcement": { "type": "string", "enum": ["error", "warn", "off"] },
|
|
296
|
-
"blueprint_enforcement": { "type": "string", "enum": ["warn", "off"] }
|
|
310
|
+
"blueprint_enforcement": { "type": "string", "enum": ["warn", "off"] },
|
|
311
|
+
"interactions_enforcement": {
|
|
312
|
+
"type": "string",
|
|
313
|
+
"enum": ["error", "warn", "off"],
|
|
314
|
+
"description": "v2.1 C5. Severity for the experiential interactions guard rule (8th rule). Defaults: creative → off, guided → warn, strict → error."
|
|
315
|
+
}
|
|
297
316
|
}
|
|
298
317
|
},
|
|
299
318
|
"SeoHints": {
|
|
@@ -394,6 +413,10 @@
|
|
|
394
413
|
"match_case": {
|
|
395
414
|
"type": "boolean",
|
|
396
415
|
"description": "If true: hotkey key matching is case-sensitive (distinguishes 'g' from 'G'). Default: false — uppercase letter implies Shift modifier."
|
|
416
|
+
},
|
|
417
|
+
"show_chord_indicator": {
|
|
418
|
+
"type": "boolean",
|
|
419
|
+
"description": "v2.1 C3. If true (default): render the .d-hotkey-indicator corner badge when a chord hotkey prefix is armed. If false: silent chord tracking (no visual feedback)."
|
|
397
420
|
}
|
|
398
421
|
}
|
|
399
422
|
},
|