@decantr/core 1.0.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +48 -10
- package/dist/index.js +183 -180
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/schema/execution-pack.common.v1.json +12 -0
- package/schema/page-pack.v1.json +5 -0
- package/schema/scaffold-pack.v1.json +75 -0
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install @decantr/core
|
|
|
15
15
|
|
|
16
16
|
## Stability
|
|
17
17
|
|
|
18
|
-
`@decantr/core` is published for advanced package consumers that need low-level execution-pack primitives. It is stable in the `
|
|
18
|
+
`@decantr/core` is published for advanced package consumers that need low-level execution-pack primitives. It is stable in the `2.x` line for the documented exports in this package, but it is still not the recommended first integration surface for most Decantr adopters.
|
|
19
19
|
|
|
20
20
|
## What It Exports
|
|
21
21
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StructurePage, EssenceFile,
|
|
1
|
+
import { StructurePage, EssenceFile, EssenceV4 } from '@decantr/essence-spec';
|
|
2
2
|
import { Pattern, ResolvedPreset, Theme, ContentResolver } from '@decantr/registry';
|
|
3
3
|
|
|
4
4
|
type IRNodeType = 'app' | 'shell' | 'page' | 'pattern' | 'grid' | 'nav' | 'store';
|
|
@@ -42,7 +42,7 @@ interface IRPatternMeta {
|
|
|
42
42
|
*/
|
|
43
43
|
presetDescription?: string;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* Declared runtime interactions from the pattern JSON.
|
|
46
46
|
* Page-pack renderer surfaces these as a checkbox checklist.
|
|
47
47
|
*/
|
|
48
48
|
interactions?: string[];
|
|
@@ -92,7 +92,7 @@ interface IRRoute {
|
|
|
92
92
|
shell: string;
|
|
93
93
|
sectionId?: string;
|
|
94
94
|
}
|
|
95
|
-
/** Which
|
|
95
|
+
/** Which Essence v4 layer sourced this node */
|
|
96
96
|
type IRLayer = 'dna' | 'blueprint' | 'meta';
|
|
97
97
|
interface IRNode {
|
|
98
98
|
type: IRNodeType;
|
|
@@ -100,7 +100,7 @@ interface IRNode {
|
|
|
100
100
|
children: IRNode[];
|
|
101
101
|
spatial?: IRSpatial;
|
|
102
102
|
meta?: Record<string, unknown>;
|
|
103
|
-
/** When built from
|
|
103
|
+
/** When built from an Essence v4 document, indicates the originating layer */
|
|
104
104
|
layer?: IRLayer;
|
|
105
105
|
}
|
|
106
106
|
interface IRAppNode extends IRNode {
|
|
@@ -407,7 +407,7 @@ interface PagePackPattern {
|
|
|
407
407
|
*/
|
|
408
408
|
presetDescription?: string;
|
|
409
409
|
/**
|
|
410
|
-
*
|
|
410
|
+
* Declared interactions from the pattern JSON. Rendered
|
|
411
411
|
* as a checkbox checklist so cold LLMs in generation mode see a
|
|
412
412
|
* hard-edged list they can't categorize as "philosophy". Enforced by
|
|
413
413
|
* decantr check --strict (C5 guard rule).
|
|
@@ -544,8 +544,8 @@ interface CompileExecutionPackBundleOptions {
|
|
|
544
544
|
}
|
|
545
545
|
declare function renderExecutionPackMarkdown(pack: ExecutionPackBase<unknown>): string;
|
|
546
546
|
declare function resolvePackAdapter(target: string | undefined, platformType: string | undefined): string;
|
|
547
|
-
declare function listPackSections(essence:
|
|
548
|
-
declare function listPackPages(essence:
|
|
547
|
+
declare function listPackSections(essence: EssenceV4): SectionPackInput[];
|
|
548
|
+
declare function listPackPages(essence: EssenceV4): PagePackInput[];
|
|
549
549
|
declare function buildScaffoldPack(appNode: IRAppNode, options?: ScaffoldPackBuilderOptions): ScaffoldExecutionPack;
|
|
550
550
|
declare function buildSectionPack(appNode: IRAppNode, input: SectionPackInput, options?: SectionPackBuilderOptions): SectionExecutionPack;
|
|
551
551
|
declare function buildPagePack(appNode: IRAppNode, input: PagePackInput, options?: PagePackBuilderOptions): PageExecutionPack;
|
|
@@ -585,6 +585,44 @@ interface PipelineResult {
|
|
|
585
585
|
*/
|
|
586
586
|
declare function runPipeline(essence: EssenceFile, options: PipelineOptions): Promise<PipelineResult>;
|
|
587
587
|
|
|
588
|
+
type RealizationAdapter = 'react-vite' | 'next-app' | 'generic-web' | string;
|
|
589
|
+
interface RealizationRoute {
|
|
590
|
+
path: string;
|
|
591
|
+
sectionId: string;
|
|
592
|
+
sectionRole: string;
|
|
593
|
+
pageId: string;
|
|
594
|
+
shell: string;
|
|
595
|
+
patterns: string[];
|
|
596
|
+
states: Array<'empty' | 'loading' | 'error'>;
|
|
597
|
+
}
|
|
598
|
+
interface RealizationMockDataSeed {
|
|
599
|
+
id: string;
|
|
600
|
+
source: 'feature' | 'route';
|
|
601
|
+
shape: Record<string, unknown>;
|
|
602
|
+
}
|
|
603
|
+
interface RealizationInteractionPlaceholder {
|
|
604
|
+
id: string;
|
|
605
|
+
kind: 'command-palette' | 'hotkey' | 'auth-mock' | 'route-action';
|
|
606
|
+
route?: string;
|
|
607
|
+
label: string;
|
|
608
|
+
}
|
|
609
|
+
interface RealizationPlan {
|
|
610
|
+
version: '1.0.0';
|
|
611
|
+
sourceEssenceVersion: '4.0.0';
|
|
612
|
+
adapter: RealizationAdapter;
|
|
613
|
+
canRealizeFrameworkCode: boolean;
|
|
614
|
+
routes: RealizationRoute[];
|
|
615
|
+
shell: {
|
|
616
|
+
id: string;
|
|
617
|
+
theme: string;
|
|
618
|
+
mode: string;
|
|
619
|
+
};
|
|
620
|
+
mockData: RealizationMockDataSeed[];
|
|
621
|
+
interactions: RealizationInteractionPlaceholder[];
|
|
622
|
+
unsupportedReason?: string;
|
|
623
|
+
}
|
|
624
|
+
declare function compileRealizationPlan(essence: EssenceV4): RealizationPlan;
|
|
625
|
+
|
|
588
626
|
interface ResolvedPage {
|
|
589
627
|
page: ResolvedStructurePage;
|
|
590
628
|
patterns: Map<string, {
|
|
@@ -609,8 +647,8 @@ interface ResolvedEssence {
|
|
|
609
647
|
shell: IRShellConfig;
|
|
610
648
|
routes: IRRoute[];
|
|
611
649
|
features: string[];
|
|
612
|
-
/** True when the source essence
|
|
613
|
-
|
|
650
|
+
/** True when the source essence uses the active DNA/Blueprint/Meta contract. */
|
|
651
|
+
isBlueprintSource: boolean;
|
|
614
652
|
}
|
|
615
653
|
declare function resolveVisualEffects(theme: Theme, pattern: Pattern, _slot?: string): IRVisualEffect | null;
|
|
616
654
|
/** Resolve all external references in an Essence file */
|
|
@@ -619,4 +657,4 @@ declare function resolveEssence(essence: EssenceFile, resolver: ContentResolver)
|
|
|
619
657
|
/** Convert a kebab-case or snake_case string to PascalCase */
|
|
620
658
|
declare function pascalCase(str: string): string;
|
|
621
659
|
|
|
622
|
-
export { type CompileExecutionPackBundleOptions, EXECUTION_PACK_BUNDLE_SCHEMA_URL, EXECUTION_PACK_SCHEMA_URLS, type ExecutionPackAntiPattern, type ExecutionPackBase, type ExecutionPackBundle, type ExecutionPackExample, type ExecutionPackManifest, type ExecutionPackScope, type ExecutionPackSelector, type ExecutionPackSuccessCheck, type ExecutionPackTarget, type ExecutionPackTokenBudget, type ExecutionPackType, type IRAppNode, type IRBreakpointEntry, type IRCardWrapping, type IRGridNode, type IRHookType, type IRLayer, type IRNavItem, type IRNode, type IRNodeType, type IRPageNode, type IRPatternMeta, type IRPatternNode, type IRRoute, type IRShellConfig, type IRShellNode, type IRSpatial, type IRStoreNode, type IRTheme, type IRThemeDecoration, type IRVisualEffect, type IRWiring, type IRWiringSignal, type MutationExecutionPack, type MutationPackBuilderOptions, type MutationPackData, type MutationPackKind, PACK_MANIFEST_SCHEMA_URL, type PackManifestEntry, type PackManifestMutationEntry, type PackManifestPageEntry, type PackManifestSectionEntry, type PageExecutionPack, type PagePackBuilderOptions, type PagePackData, type PagePackInput, type PagePackPattern, type PipelineOptions, type PipelineResult, type ResolvedEssence, type ResolvedPage, type ReviewExecutionPack, type ReviewPackBuilderOptions, type ReviewPackData, type ReviewPackKind, SELECTED_EXECUTION_PACK_SCHEMA_URL, type ScaffoldExecutionPack, type ScaffoldPackBuilderOptions, type ScaffoldPackData, type ScaffoldPackRoute, type SectionExecutionPack, type SectionPackBuilderOptions, type SectionPackData, type SectionPackInput, type SectionPackRoute, type SelectedExecutionPack, type SelectedExecutionPackResponse, buildMutationPack, buildPageIR, buildPagePack, buildReviewPack, buildScaffoldPack, buildSectionPack, compileExecutionPackBundle, compileSelectedExecutionPack, countPatterns, findNodes, listPackPages, listPackSections, pascalCase, renderExecutionPackMarkdown, resolveEssence, resolvePackAdapter, resolveVisualEffects, runPipeline, selectExecutionPackFromBundle, validateIR, walkIR };
|
|
660
|
+
export { type CompileExecutionPackBundleOptions, EXECUTION_PACK_BUNDLE_SCHEMA_URL, EXECUTION_PACK_SCHEMA_URLS, type ExecutionPackAntiPattern, type ExecutionPackBase, type ExecutionPackBundle, type ExecutionPackExample, type ExecutionPackManifest, type ExecutionPackScope, type ExecutionPackSelector, type ExecutionPackSuccessCheck, type ExecutionPackTarget, type ExecutionPackTokenBudget, type ExecutionPackType, type IRAppNode, type IRBreakpointEntry, type IRCardWrapping, type IRGridNode, type IRHookType, type IRLayer, type IRNavItem, type IRNode, type IRNodeType, type IRPageNode, type IRPatternMeta, type IRPatternNode, type IRRoute, type IRShellConfig, type IRShellNode, type IRSpatial, type IRStoreNode, type IRTheme, type IRThemeDecoration, type IRVisualEffect, type IRWiring, type IRWiringSignal, type MutationExecutionPack, type MutationPackBuilderOptions, type MutationPackData, type MutationPackKind, PACK_MANIFEST_SCHEMA_URL, type PackManifestEntry, type PackManifestMutationEntry, type PackManifestPageEntry, type PackManifestSectionEntry, type PageExecutionPack, type PagePackBuilderOptions, type PagePackData, type PagePackInput, type PagePackPattern, type PipelineOptions, type PipelineResult, type RealizationAdapter, type RealizationInteractionPlaceholder, type RealizationMockDataSeed, type RealizationPlan, type RealizationRoute, type ResolvedEssence, type ResolvedPage, type ReviewExecutionPack, type ReviewPackBuilderOptions, type ReviewPackData, type ReviewPackKind, SELECTED_EXECUTION_PACK_SCHEMA_URL, type ScaffoldExecutionPack, type ScaffoldPackBuilderOptions, type ScaffoldPackData, type ScaffoldPackRoute, type SectionExecutionPack, type SectionPackBuilderOptions, type SectionPackData, type SectionPackInput, type SectionPackRoute, type SelectedExecutionPack, type SelectedExecutionPackResponse, buildMutationPack, buildPageIR, buildPagePack, buildReviewPack, buildScaffoldPack, buildSectionPack, compileExecutionPackBundle, compileRealizationPlan, compileSelectedExecutionPack, countPatterns, findNodes, listPackPages, listPackSections, pascalCase, renderExecutionPackMarkdown, resolveEssence, resolvePackAdapter, resolveVisualEffects, runPipeline, selectExecutionPackFromBundle, validateIR, walkIR };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/resolve.ts
|
|
2
|
-
import { computeDensity,
|
|
2
|
+
import { computeDensity, isV4 } from "@decantr/essence-spec";
|
|
3
3
|
import { detectWirings, resolvePatternPreset } from "@decantr/registry";
|
|
4
4
|
|
|
5
5
|
// src/utils.ts
|
|
@@ -115,15 +115,7 @@ function buildThemeDecoration(theme) {
|
|
|
115
115
|
dimensions: shell.dimensions || null
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
|
-
function
|
|
119
|
-
return {
|
|
120
|
-
id: essence.theme.id,
|
|
121
|
-
mode: essence.theme.mode,
|
|
122
|
-
shape: essence.theme.shape || null,
|
|
123
|
-
isAddon
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
function buildThemeFromV3(essence, isAddon) {
|
|
118
|
+
function buildThemeFromV4(essence, isAddon) {
|
|
127
119
|
const dna = essence.dna;
|
|
128
120
|
return {
|
|
129
121
|
id: dna.theme.id,
|
|
@@ -145,7 +137,7 @@ function blueprintPageToStructurePage(page, defaultShell, sectionId) {
|
|
|
145
137
|
function routeIdentity(pageId, sectionId) {
|
|
146
138
|
return sectionId ? `${sectionId}:${pageId}` : pageId;
|
|
147
139
|
}
|
|
148
|
-
function
|
|
140
|
+
function buildV4Routes(essence, structurePages) {
|
|
149
141
|
const explicitRoutes = /* @__PURE__ */ new Map();
|
|
150
142
|
for (const [path, entry] of Object.entries(essence.blueprint.routes ?? {})) {
|
|
151
143
|
if (!entry?.page) continue;
|
|
@@ -230,81 +222,14 @@ function resolveVisualEffects(theme, pattern, _slot) {
|
|
|
230
222
|
};
|
|
231
223
|
}
|
|
232
224
|
async function resolveEssence(essence, resolver) {
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (isSimple(essence)) {
|
|
238
|
-
simpleEssence = essence;
|
|
239
|
-
} else if (isSectioned(essence)) {
|
|
240
|
-
const sectioned = essence;
|
|
241
|
-
if (sectioned.sections.length > 1) {
|
|
242
|
-
throw new Error(
|
|
243
|
-
`Sectioned essences with ${sectioned.sections.length} sections are not yet supported. Only single-section sectioned essences can be processed. Consider migrating to v3 format using migrateV2ToV3().`
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
const firstSection = sectioned.sections[0];
|
|
247
|
-
simpleEssence = {
|
|
248
|
-
version: sectioned.version,
|
|
249
|
-
archetype: firstSection.archetype,
|
|
250
|
-
theme: firstSection.theme,
|
|
251
|
-
personality: sectioned.personality,
|
|
252
|
-
platform: sectioned.platform,
|
|
253
|
-
structure: firstSection.structure,
|
|
254
|
-
features: firstSection.features || [],
|
|
255
|
-
density: sectioned.density,
|
|
256
|
-
guard: sectioned.guard,
|
|
257
|
-
target: sectioned.target
|
|
258
|
-
};
|
|
259
|
-
} else {
|
|
260
|
-
throw new Error("Invalid essence format");
|
|
261
|
-
}
|
|
262
|
-
let registryTheme = null;
|
|
263
|
-
const themeResult = await resolver.resolve("theme", simpleEssence.theme.id);
|
|
264
|
-
if (themeResult) {
|
|
265
|
-
registryTheme = themeResult.item;
|
|
225
|
+
if (!isV4(essence)) {
|
|
226
|
+
throw new Error(
|
|
227
|
+
"Active Decantr V2 workflows require Essence v4.0.0. Run `decantr migrate --to v4` for older essence files."
|
|
228
|
+
);
|
|
266
229
|
}
|
|
267
|
-
|
|
268
|
-
const density = computeDensity(
|
|
269
|
-
simpleEssence.personality,
|
|
270
|
-
themeSpatial ? {
|
|
271
|
-
density_bias: themeSpatial.density_bias,
|
|
272
|
-
content_gap_shift: themeSpatial.content_gap_shift
|
|
273
|
-
} : void 0
|
|
274
|
-
);
|
|
275
|
-
const themeId = simpleEssence.theme.id;
|
|
276
|
-
const isAddon = themeId.startsWith("custom:") || !CORE_STYLES.has(themeId);
|
|
277
|
-
const theme = buildTheme(simpleEssence, isAddon);
|
|
278
|
-
const resolvedPages = await resolvePages(simpleEssence.structure, resolver, registryTheme);
|
|
279
|
-
const shellType = simpleEssence.structure[0]?.shell || "sidebar-main";
|
|
280
|
-
const brand = pascalCase(simpleEssence.archetype);
|
|
281
|
-
const nav = buildNavItems(simpleEssence.structure);
|
|
282
|
-
const decoration = registryTheme ? buildThemeDecoration(registryTheme) : null;
|
|
283
|
-
const shell = {
|
|
284
|
-
type: shellType,
|
|
285
|
-
brand,
|
|
286
|
-
nav,
|
|
287
|
-
inset: false,
|
|
288
|
-
decoration
|
|
289
|
-
};
|
|
290
|
-
const routes = simpleEssence.structure.map((page, i) => ({
|
|
291
|
-
path: routePath(page.id, i),
|
|
292
|
-
pageId: page.id,
|
|
293
|
-
shell: page.shell
|
|
294
|
-
}));
|
|
295
|
-
return {
|
|
296
|
-
essence,
|
|
297
|
-
pages: resolvedPages,
|
|
298
|
-
registryTheme,
|
|
299
|
-
density: { gap: density.content_gap, level: density.level },
|
|
300
|
-
theme,
|
|
301
|
-
shell,
|
|
302
|
-
routes,
|
|
303
|
-
features: simpleEssence.features ?? [],
|
|
304
|
-
isV3Source: false
|
|
305
|
-
};
|
|
230
|
+
return resolveV4Essence(essence, resolver);
|
|
306
231
|
}
|
|
307
|
-
async function
|
|
232
|
+
async function resolveV4Essence(essence, resolver) {
|
|
308
233
|
const { dna, blueprint, meta } = essence;
|
|
309
234
|
let registryTheme = null;
|
|
310
235
|
const themeResult = await resolver.resolve("theme", dna.theme.id);
|
|
@@ -325,22 +250,17 @@ async function resolveV3Essence(essence, resolver) {
|
|
|
325
250
|
};
|
|
326
251
|
const themeId = dna.theme.id;
|
|
327
252
|
const isAddon = themeId.startsWith("custom:") || !CORE_STYLES.has(themeId);
|
|
328
|
-
const theme =
|
|
329
|
-
const defaultShell = blueprint.shell ?? blueprint.sections
|
|
330
|
-
const structurePages = blueprint.
|
|
253
|
+
const theme = buildThemeFromV4(essence, isAddon);
|
|
254
|
+
const defaultShell = blueprint.shell ?? blueprint.sections[0]?.shell ?? "sidebar-main";
|
|
255
|
+
const structurePages = blueprint.sections.flatMap(
|
|
331
256
|
(section) => section.pages.map(
|
|
332
257
|
(page) => blueprintPageToStructurePage(page, section.shell ?? defaultShell, section.id)
|
|
333
258
|
)
|
|
334
|
-
)
|
|
335
|
-
blueprintPageToStructurePage(
|
|
336
|
-
{ id: "home", layout: ["hero"] },
|
|
337
|
-
defaultShell
|
|
338
|
-
)
|
|
339
|
-
];
|
|
259
|
+
);
|
|
340
260
|
const resolvedPages = await resolvePages(structurePages, resolver, registryTheme);
|
|
341
261
|
const shellType = defaultShell;
|
|
342
262
|
const brand = pascalCase(meta.archetype);
|
|
343
|
-
const routes =
|
|
263
|
+
const routes = buildV4Routes(essence, structurePages);
|
|
344
264
|
const nav = buildNavItems(structurePages, routes);
|
|
345
265
|
const decoration = registryTheme ? buildThemeDecoration(registryTheme) : null;
|
|
346
266
|
const shell = {
|
|
@@ -359,7 +279,7 @@ async function resolveV3Essence(essence, resolver) {
|
|
|
359
279
|
shell,
|
|
360
280
|
routes,
|
|
361
281
|
features: blueprint.features ?? [],
|
|
362
|
-
|
|
282
|
+
isBlueprintSource: true
|
|
363
283
|
};
|
|
364
284
|
}
|
|
365
285
|
async function resolvePages(pages, resolver, registryTheme) {
|
|
@@ -558,23 +478,19 @@ function validateIR(root) {
|
|
|
558
478
|
}
|
|
559
479
|
|
|
560
480
|
// src/packs.ts
|
|
561
|
-
import {
|
|
481
|
+
import { isV4 as isV42 } from "@decantr/essence-spec";
|
|
562
482
|
|
|
563
483
|
// src/pipeline.ts
|
|
564
|
-
import {
|
|
484
|
+
import { validateEssence } from "@decantr/essence-spec";
|
|
565
485
|
import { createResolver } from "@decantr/registry";
|
|
566
486
|
function extractRouting(essence) {
|
|
567
|
-
|
|
568
|
-
return essence.meta.platform.routing || "history";
|
|
569
|
-
}
|
|
570
|
-
return essence.platform?.routing || "history";
|
|
487
|
+
return essence.meta.platform.routing || "history";
|
|
571
488
|
}
|
|
572
489
|
async function runPipeline(essence, options) {
|
|
573
490
|
const validation = validateEssence(essence);
|
|
574
491
|
if (!validation.valid) {
|
|
575
492
|
throw new Error(`Invalid essence: ${validation.errors.join(", ")}`);
|
|
576
493
|
}
|
|
577
|
-
const effectiveEssence = isV32(essence) ? essence : migrateV2ToV3(essence);
|
|
578
494
|
const resolver = options.resolver ?? (() => {
|
|
579
495
|
if (!options.contentRoot) {
|
|
580
496
|
throw new Error("Pipeline options must include either a contentRoot or a resolver.");
|
|
@@ -584,8 +500,8 @@ async function runPipeline(essence, options) {
|
|
|
584
500
|
overridePaths: options.overridePaths
|
|
585
501
|
});
|
|
586
502
|
})();
|
|
587
|
-
const resolved = await resolveEssence(
|
|
588
|
-
const layer =
|
|
503
|
+
const resolved = await resolveEssence(essence, resolver);
|
|
504
|
+
const layer = "blueprint";
|
|
589
505
|
const pageNodes = [];
|
|
590
506
|
for (const rp of resolved.pages) {
|
|
591
507
|
const pageIR = buildPageIR(
|
|
@@ -779,13 +695,13 @@ var DEFAULT_REVIEW_ANTI_PATTERNS = [
|
|
|
779
695
|
}
|
|
780
696
|
];
|
|
781
697
|
function collectPatternIds(page) {
|
|
782
|
-
const
|
|
698
|
+
const patternIds2 = [];
|
|
783
699
|
walkIR(page, (node) => {
|
|
784
700
|
if (node.type !== "pattern") return;
|
|
785
701
|
const patternNode = node;
|
|
786
|
-
|
|
702
|
+
patternIds2.push(patternNode.pattern.patternId);
|
|
787
703
|
});
|
|
788
|
-
return [...new Set(
|
|
704
|
+
return [...new Set(patternIds2)];
|
|
789
705
|
}
|
|
790
706
|
function pageIdentity(pageId, sectionId) {
|
|
791
707
|
return sectionId ? `${sectionId}/${pageId}` : pageId;
|
|
@@ -882,6 +798,16 @@ function routingImplementationHint(routing) {
|
|
|
882
798
|
}
|
|
883
799
|
function renderExecutionPackMarkdown(pack) {
|
|
884
800
|
const lines = [];
|
|
801
|
+
const escapeMarkdownCell = (value) => {
|
|
802
|
+
let escaped = "";
|
|
803
|
+
for (const char of value) {
|
|
804
|
+
if (char === "\\") escaped += "\\\\";
|
|
805
|
+
else if (char === "|") escaped += "\\|";
|
|
806
|
+
else if (char === "\n" || char === "\r") escaped += "<br>";
|
|
807
|
+
else escaped += char;
|
|
808
|
+
}
|
|
809
|
+
return escaped;
|
|
810
|
+
};
|
|
885
811
|
lines.push(`# ${pack.packType.charAt(0).toUpperCase()}${pack.packType.slice(1)} Pack`);
|
|
886
812
|
lines.push("");
|
|
887
813
|
lines.push(`**Objective:** ${pack.objective}`);
|
|
@@ -960,7 +886,6 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
960
886
|
}
|
|
961
887
|
lines.push("");
|
|
962
888
|
if (scaffoldPack.data.themeDecorators && scaffoldPack.data.themeDecorators.length > 0) {
|
|
963
|
-
const escScaffoldCell = (s) => s.replace(/\|/g, "\\|");
|
|
964
889
|
lines.push(`## Required Theme Decorators (${scaffoldPack.data.theme.id})`);
|
|
965
890
|
lines.push("");
|
|
966
891
|
lines.push(
|
|
@@ -971,7 +896,7 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
971
896
|
lines.push("|-------|--------|----------|");
|
|
972
897
|
for (const entry of scaffoldPack.data.themeDecorators) {
|
|
973
898
|
lines.push(
|
|
974
|
-
`| \`.${entry.class}\` | ${
|
|
899
|
+
`| \`.${entry.class}\` | ${escapeMarkdownCell(entry.intent)} | ${escapeMarkdownCell(entry.applyTo)} |`
|
|
975
900
|
);
|
|
976
901
|
}
|
|
977
902
|
lines.push("");
|
|
@@ -1029,7 +954,6 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
1029
954
|
lines.push("");
|
|
1030
955
|
}
|
|
1031
956
|
if (sectionPack.data.themeDecorators && sectionPack.data.themeDecorators.length > 0) {
|
|
1032
|
-
const escCell = (s) => s.replace(/\|/g, "\\|");
|
|
1033
957
|
lines.push(`## Required Theme Decorators (${sectionPack.data.theme.id})`);
|
|
1034
958
|
lines.push("");
|
|
1035
959
|
lines.push(
|
|
@@ -1040,7 +964,7 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
1040
964
|
lines.push("|-------|--------|----------|");
|
|
1041
965
|
for (const entry of sectionPack.data.themeDecorators) {
|
|
1042
966
|
lines.push(
|
|
1043
|
-
`| \`.${entry.class}\` | ${
|
|
967
|
+
`| \`.${entry.class}\` | ${escapeMarkdownCell(entry.intent)} | ${escapeMarkdownCell(entry.applyTo)} |`
|
|
1044
968
|
);
|
|
1045
969
|
}
|
|
1046
970
|
lines.push("");
|
|
@@ -1080,7 +1004,9 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
1080
1004
|
lines.push(` > ${pattern.presetDescription}`);
|
|
1081
1005
|
}
|
|
1082
1006
|
if (pattern.interactions && pattern.interactions.length > 0) {
|
|
1083
|
-
lines.push(
|
|
1007
|
+
lines.push(
|
|
1008
|
+
` **Interactions (MUST implement each \u2014 see DECANTR.md "Interaction Requirements"):**`
|
|
1009
|
+
);
|
|
1084
1010
|
for (const interaction of pattern.interactions) {
|
|
1085
1011
|
lines.push(` - [ ] ${interaction}`);
|
|
1086
1012
|
}
|
|
@@ -1225,70 +1151,42 @@ function resolvePackAdapter(target, platformType) {
|
|
|
1225
1151
|
}
|
|
1226
1152
|
function listPackSections(essence) {
|
|
1227
1153
|
const declaredSections = essence.blueprint.sections;
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
...Array.isArray(section.directives) && section.directives.length > 0 ? { directives: section.directives } : {}
|
|
1247
|
-
};
|
|
1248
|
-
}).filter((section) => section.pageIds.length > 0);
|
|
1249
|
-
}
|
|
1250
|
-
const pages = essence.blueprint.pages ?? [{ id: "home", layout: ["hero"] }];
|
|
1251
|
-
return [
|
|
1252
|
-
{
|
|
1253
|
-
id: essence.meta.archetype || "default",
|
|
1254
|
-
role: "primary",
|
|
1255
|
-
shell: essence.blueprint.shell ?? "sidebar-main",
|
|
1256
|
-
description: `${essence.meta.archetype || "Application"} section`,
|
|
1257
|
-
features: essence.blueprint.features || [],
|
|
1258
|
-
pageIds: pages.map((page) => page.id)
|
|
1259
|
-
}
|
|
1260
|
-
];
|
|
1154
|
+
const routedSectionPages = new Set(
|
|
1155
|
+
Object.values(essence.blueprint.routes ?? {}).map((entry) => `${entry.section}:${entry.page}`)
|
|
1156
|
+
);
|
|
1157
|
+
return declaredSections.map((section) => {
|
|
1158
|
+
const pageIds = section.pages.filter(
|
|
1159
|
+
(page) => routedSectionPages.size === 0 || routedSectionPages.has(`${section.id}:${page.id}`)
|
|
1160
|
+
).map((page) => page.id);
|
|
1161
|
+
return {
|
|
1162
|
+
id: section.id,
|
|
1163
|
+
role: section.role,
|
|
1164
|
+
shell: section.shell,
|
|
1165
|
+
description: section.description,
|
|
1166
|
+
features: section.features,
|
|
1167
|
+
pageIds,
|
|
1168
|
+
...Array.isArray(section.navigation_items) && section.navigation_items.length > 0 ? { navigationItems: section.navigation_items } : {},
|
|
1169
|
+
...Array.isArray(section.directives) && section.directives.length > 0 ? { directives: section.directives } : {}
|
|
1170
|
+
};
|
|
1171
|
+
}).filter((section) => section.pageIds.length > 0);
|
|
1261
1172
|
}
|
|
1262
1173
|
function listPackPages(essence) {
|
|
1263
1174
|
const declaredSections = essence.blueprint.sections;
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
(page) => routedSectionPages.size === 0 || routedSectionPages.has(`${page.sectionId}:${page.pageId}`)
|
|
1280
|
-
)
|
|
1281
|
-
);
|
|
1282
|
-
}
|
|
1283
|
-
const pages = essence.blueprint.pages ?? [{ id: "home", layout: ["hero"] }];
|
|
1284
|
-
const defaultShell = essence.blueprint.shell ?? "sidebar-main";
|
|
1285
|
-
return pages.map((page) => ({
|
|
1286
|
-
pageId: page.id,
|
|
1287
|
-
shell: page.shell_override ?? defaultShell,
|
|
1288
|
-
sectionId: essence.meta.archetype || "default",
|
|
1289
|
-
sectionRole: "primary",
|
|
1290
|
-
features: essence.blueprint.features || []
|
|
1291
|
-
}));
|
|
1175
|
+
const routedSectionPages = new Set(
|
|
1176
|
+
Object.values(essence.blueprint.routes ?? {}).map((entry) => `${entry.section}:${entry.page}`)
|
|
1177
|
+
);
|
|
1178
|
+
return declaredSections.flatMap(
|
|
1179
|
+
(section) => section.pages.map((page) => ({
|
|
1180
|
+
pageId: page.id,
|
|
1181
|
+
shell: page.shell_override ?? section.shell,
|
|
1182
|
+
sectionId: section.id,
|
|
1183
|
+
sectionRole: section.role,
|
|
1184
|
+
features: section.features,
|
|
1185
|
+
...Array.isArray(page.directives) && page.directives.length > 0 ? { directives: page.directives } : {}
|
|
1186
|
+
})).filter(
|
|
1187
|
+
(page) => routedSectionPages.size === 0 || routedSectionPages.has(`${page.sectionId}:${page.pageId}`)
|
|
1188
|
+
)
|
|
1189
|
+
);
|
|
1292
1190
|
}
|
|
1293
1191
|
function buildPageManifestEntries(pages) {
|
|
1294
1192
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -1618,19 +1516,23 @@ function buildReviewPack(appNode, options = {}) {
|
|
|
1618
1516
|
return pack;
|
|
1619
1517
|
}
|
|
1620
1518
|
async function compileExecutionPackBundle(essence, options = {}) {
|
|
1621
|
-
|
|
1519
|
+
if (!isV42(essence)) {
|
|
1520
|
+
throw new Error(
|
|
1521
|
+
"Active Decantr V2 workflows require Essence v4.0.0. Run `decantr migrate --to v4` for older essence files."
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1622
1524
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1623
1525
|
const sharedTarget = {
|
|
1624
|
-
framework:
|
|
1625
|
-
runtime:
|
|
1626
|
-
adapter: resolvePackAdapter(
|
|
1526
|
+
framework: essence.meta.target || null,
|
|
1527
|
+
runtime: essence.meta.platform.type || null,
|
|
1528
|
+
adapter: resolvePackAdapter(essence.meta.target, essence.meta.platform.type)
|
|
1627
1529
|
};
|
|
1628
1530
|
const pipeline = await runPipeline(essence, {
|
|
1629
1531
|
contentRoot: options.contentRoot,
|
|
1630
1532
|
overridePaths: options.overridePaths,
|
|
1631
1533
|
resolver: options.resolver
|
|
1632
1534
|
});
|
|
1633
|
-
const navMeta =
|
|
1535
|
+
const navMeta = essence.meta.navigation;
|
|
1634
1536
|
const commandPaletteValue = typeof navMeta?.command_palette === "object" && navMeta.command_palette !== null ? navMeta.command_palette : Boolean(navMeta?.command_palette);
|
|
1635
1537
|
const themeDecorators = (() => {
|
|
1636
1538
|
const defs = pipeline.registryTheme?.decorator_definitions;
|
|
@@ -1665,8 +1567,8 @@ async function compileExecutionPackBundle(essence, options = {}) {
|
|
|
1665
1567
|
const review = buildReviewPack(pipeline.ir, {
|
|
1666
1568
|
target: sharedTarget
|
|
1667
1569
|
});
|
|
1668
|
-
const sectionInputs = listPackSections(
|
|
1669
|
-
const pageInputs = listPackPages(
|
|
1570
|
+
const sectionInputs = listPackSections(essence);
|
|
1571
|
+
const pageInputs = listPackPages(essence);
|
|
1670
1572
|
const sections = sectionInputs.map(
|
|
1671
1573
|
(section) => buildSectionPack(pipeline.ir, section, {
|
|
1672
1574
|
target: sharedTarget
|
|
@@ -1773,6 +1675,106 @@ async function compileSelectedExecutionPack(essence, selector, options = {}) {
|
|
|
1773
1675
|
const bundle = await compileExecutionPackBundle(essence, options);
|
|
1774
1676
|
return selectExecutionPackFromBundle(bundle, selector);
|
|
1775
1677
|
}
|
|
1678
|
+
|
|
1679
|
+
// src/realization.ts
|
|
1680
|
+
import { isV4 as isV43 } from "@decantr/essence-spec";
|
|
1681
|
+
var CERTIFIED_REALIZATION_ADAPTERS = /* @__PURE__ */ new Set(["react-vite", "next-app"]);
|
|
1682
|
+
function routePath2(page, fallbackIndex) {
|
|
1683
|
+
if (page.route) return page.route;
|
|
1684
|
+
if (page.id === "home" || fallbackIndex === 0) return "/";
|
|
1685
|
+
return `/${page.id}`;
|
|
1686
|
+
}
|
|
1687
|
+
function patternIds(layout) {
|
|
1688
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1689
|
+
for (const item of layout) {
|
|
1690
|
+
if (typeof item === "string") {
|
|
1691
|
+
ids.add(item);
|
|
1692
|
+
} else if ("pattern" in item) {
|
|
1693
|
+
ids.add(item.pattern);
|
|
1694
|
+
} else if ("cols" in item) {
|
|
1695
|
+
for (const col of item.cols) {
|
|
1696
|
+
ids.add(typeof col === "string" ? col : col.pattern);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
return [...ids];
|
|
1701
|
+
}
|
|
1702
|
+
function compileRealizationPlan(essence) {
|
|
1703
|
+
if (!isV43(essence)) {
|
|
1704
|
+
throw new Error(
|
|
1705
|
+
"Active Decantr V2 workflows require Essence v4.0.0. Run `decantr migrate --to v4` for older essence files."
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
const packAdapter = resolvePackAdapter(essence.meta.target, essence.meta.platform.type);
|
|
1709
|
+
const adapter = essence.meta.target === "nextjs" ? "next-app" : packAdapter;
|
|
1710
|
+
const canRealizeFrameworkCode = CERTIFIED_REALIZATION_ADAPTERS.has(adapter);
|
|
1711
|
+
const routes = [];
|
|
1712
|
+
for (const section of essence.blueprint.sections) {
|
|
1713
|
+
section.pages.forEach((page, pageIndex) => {
|
|
1714
|
+
routes.push({
|
|
1715
|
+
path: routePath2(page, routes.length + pageIndex),
|
|
1716
|
+
sectionId: section.id,
|
|
1717
|
+
sectionRole: section.role,
|
|
1718
|
+
pageId: page.id,
|
|
1719
|
+
shell: page.shell_override ?? section.shell,
|
|
1720
|
+
patterns: patternIds(page.layout),
|
|
1721
|
+
states: ["empty", "loading", "error"]
|
|
1722
|
+
});
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
const mockData = [
|
|
1726
|
+
...essence.blueprint.features.map((feature) => ({
|
|
1727
|
+
id: feature,
|
|
1728
|
+
source: "feature",
|
|
1729
|
+
shape: { enabled: true, status: "mocked" }
|
|
1730
|
+
})),
|
|
1731
|
+
...routes.map((route) => ({
|
|
1732
|
+
id: route.pageId,
|
|
1733
|
+
source: "route",
|
|
1734
|
+
shape: { title: route.pageId, items: [] }
|
|
1735
|
+
}))
|
|
1736
|
+
];
|
|
1737
|
+
const navigation = essence.meta.navigation;
|
|
1738
|
+
const interactions = [
|
|
1739
|
+
{
|
|
1740
|
+
id: "auth-mock",
|
|
1741
|
+
kind: "auth-mock",
|
|
1742
|
+
label: "Authenticated user/session placeholder"
|
|
1743
|
+
}
|
|
1744
|
+
];
|
|
1745
|
+
if (navigation?.command_palette) {
|
|
1746
|
+
interactions.push({
|
|
1747
|
+
id: "command-palette",
|
|
1748
|
+
kind: "command-palette",
|
|
1749
|
+
label: "Command palette placeholder"
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
for (const hotkey of navigation?.hotkeys ?? []) {
|
|
1753
|
+
interactions.push({
|
|
1754
|
+
id: `hotkey-${hotkey.key}`,
|
|
1755
|
+
kind: "hotkey",
|
|
1756
|
+
route: hotkey.route,
|
|
1757
|
+
label: hotkey.label
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
return {
|
|
1761
|
+
version: "1.0.0",
|
|
1762
|
+
sourceEssenceVersion: "4.0.0",
|
|
1763
|
+
adapter,
|
|
1764
|
+
canRealizeFrameworkCode,
|
|
1765
|
+
routes,
|
|
1766
|
+
shell: {
|
|
1767
|
+
id: essence.blueprint.shell ?? essence.blueprint.sections[0]?.shell ?? "sidebar-main",
|
|
1768
|
+
theme: essence.dna.theme.id,
|
|
1769
|
+
mode: essence.dna.theme.mode
|
|
1770
|
+
},
|
|
1771
|
+
mockData,
|
|
1772
|
+
interactions,
|
|
1773
|
+
...canRealizeFrameworkCode ? {} : {
|
|
1774
|
+
unsupportedReason: "No certified realization adapter is available for this target yet. Use the V4 contract, execution packs, prompts, and Project Health without generated framework code."
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1776
1778
|
export {
|
|
1777
1779
|
EXECUTION_PACK_BUNDLE_SCHEMA_URL,
|
|
1778
1780
|
EXECUTION_PACK_SCHEMA_URLS,
|
|
@@ -1785,6 +1787,7 @@ export {
|
|
|
1785
1787
|
buildScaffoldPack,
|
|
1786
1788
|
buildSectionPack,
|
|
1787
1789
|
compileExecutionPackBundle,
|
|
1790
|
+
compileRealizationPlan,
|
|
1788
1791
|
compileSelectedExecutionPack,
|
|
1789
1792
|
countPatterns,
|
|
1790
1793
|
findNodes,
|