@decantr/core 1.0.1 → 1.0.3
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 +127 -22
- package/dist/index.js +428 -180
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/schema/section-pack.v1.json +36 -0
package/dist/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
// src/pipeline.ts
|
|
2
|
-
import { validateEssence, isV3 as isV32, migrateV2ToV3 } from "@decantr/essence-spec";
|
|
3
|
-
import { createResolver } from "@decantr/registry";
|
|
4
|
-
|
|
5
1
|
// src/resolve.ts
|
|
6
|
-
import {
|
|
2
|
+
import { computeDensity, isSectioned, isSimple, isV3 } from "@decantr/essence-spec";
|
|
3
|
+
import { detectWirings, resolvePatternPreset } from "@decantr/registry";
|
|
7
4
|
|
|
8
5
|
// src/utils.ts
|
|
9
6
|
function pascalCase(str) {
|
|
@@ -11,7 +8,6 @@ function pascalCase(str) {
|
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
// src/resolve.ts
|
|
14
|
-
import { resolvePatternPreset, detectWirings } from "@decantr/registry";
|
|
15
11
|
var NAV_ICONS = {
|
|
16
12
|
overview: "layout-dashboard",
|
|
17
13
|
dashboard: "layout-dashboard",
|
|
@@ -58,7 +54,11 @@ function extractLayoutRefs(layout) {
|
|
|
58
54
|
refs.push({ id: item.pattern, explicitPreset: item.preset, alias: item.as });
|
|
59
55
|
} else if (isColumnLayout(item)) {
|
|
60
56
|
for (const col of item.cols) {
|
|
61
|
-
|
|
57
|
+
if (typeof col === "string") {
|
|
58
|
+
refs.push({ id: col });
|
|
59
|
+
} else {
|
|
60
|
+
refs.push({ id: col.pattern, explicitPreset: col.preset, alias: col.as });
|
|
61
|
+
}
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -249,10 +249,13 @@ async function resolveEssence(essence, resolver) {
|
|
|
249
249
|
registryTheme = themeResult.item;
|
|
250
250
|
}
|
|
251
251
|
const themeSpatial = registryTheme?.spatial;
|
|
252
|
-
const density = computeDensity(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
const density = computeDensity(
|
|
253
|
+
simpleEssence.personality,
|
|
254
|
+
themeSpatial ? {
|
|
255
|
+
density_bias: themeSpatial.density_bias,
|
|
256
|
+
content_gap_shift: themeSpatial.content_gap_shift
|
|
257
|
+
} : void 0
|
|
258
|
+
);
|
|
256
259
|
const themeId = simpleEssence.theme.id;
|
|
257
260
|
const isAddon = themeId.startsWith("custom:") || !CORE_STYLES.has(themeId);
|
|
258
261
|
const theme = buildTheme(simpleEssence, isAddon);
|
|
@@ -293,10 +296,13 @@ async function resolveV3Essence(essence, resolver) {
|
|
|
293
296
|
registryTheme = themeResult.item;
|
|
294
297
|
}
|
|
295
298
|
const themeSpatial = registryTheme?.spatial;
|
|
296
|
-
const density = computeDensity(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
const density = computeDensity(
|
|
300
|
+
dna.personality,
|
|
301
|
+
themeSpatial ? {
|
|
302
|
+
density_bias: themeSpatial.density_bias,
|
|
303
|
+
content_gap_shift: themeSpatial.content_gap_shift
|
|
304
|
+
} : void 0
|
|
305
|
+
);
|
|
300
306
|
const densityResult = {
|
|
301
307
|
gap: dna.spacing.content_gap || density.content_gap,
|
|
302
308
|
level: dna.spacing.density || density.level
|
|
@@ -305,10 +311,17 @@ async function resolveV3Essence(essence, resolver) {
|
|
|
305
311
|
const isAddon = themeId.startsWith("custom:") || !CORE_STYLES.has(themeId);
|
|
306
312
|
const theme = buildThemeFromV3(essence, isAddon);
|
|
307
313
|
const blueprintPages = blueprint.pages ?? (blueprint.sections ? blueprint.sections.flatMap((s) => s.pages) : [{ id: "home", layout: ["hero"] }]);
|
|
308
|
-
const defaultShell = blueprint.shell ??
|
|
314
|
+
const defaultShell = blueprint.shell ?? blueprint.sections?.[0]?.shell ?? "sidebar-main";
|
|
309
315
|
const structurePages = blueprint.pages ? blueprint.pages.map((page) => blueprintPageToStructurePage(page, defaultShell)) : blueprint.sections ? blueprint.sections.flatMap(
|
|
310
|
-
(section) => section.pages.map(
|
|
311
|
-
|
|
316
|
+
(section) => section.pages.map(
|
|
317
|
+
(page) => blueprintPageToStructurePage(page, section.shell ?? defaultShell)
|
|
318
|
+
)
|
|
319
|
+
) : [
|
|
320
|
+
blueprintPageToStructurePage(
|
|
321
|
+
{ id: "home", layout: ["hero"] },
|
|
322
|
+
defaultShell
|
|
323
|
+
)
|
|
324
|
+
];
|
|
312
325
|
const resolvedPages = await resolvePages(structurePages, resolver, registryTheme);
|
|
313
326
|
const shellType = defaultShell;
|
|
314
327
|
const brand = pascalCase(meta.archetype);
|
|
@@ -390,15 +403,20 @@ function buildPatternNode(patternId, alias, resolved, wiring, theme, density, la
|
|
|
390
403
|
const isStandalone = layout === "hero" || layout === "row";
|
|
391
404
|
const contained = pattern && preset ? shouldWrapInCard(pattern, preset, theme) : false;
|
|
392
405
|
const components = pattern?.components || [];
|
|
406
|
+
const presetName = preset?.preset || "default";
|
|
407
|
+
const presetDescription = pattern?.presets?.[presetName]?.description;
|
|
408
|
+
const interactions = Array.isArray(pattern?.interactions) ? pattern.interactions : void 0;
|
|
393
409
|
const patternMeta = {
|
|
394
410
|
patternId,
|
|
395
|
-
preset:
|
|
411
|
+
preset: presetName,
|
|
396
412
|
alias,
|
|
397
413
|
layout,
|
|
398
414
|
contained,
|
|
399
415
|
standalone: isStandalone,
|
|
400
416
|
code: preset?.code ? { imports: preset.code.imports, example: preset.code.example } : null,
|
|
401
|
-
components
|
|
417
|
+
components,
|
|
418
|
+
...presetDescription ? { presetDescription } : {},
|
|
419
|
+
...interactions && interactions.length > 0 ? { interactions } : {}
|
|
402
420
|
};
|
|
403
421
|
const card = contained && !isStandalone && pattern ? buildCardWrapping(pattern, theme) : null;
|
|
404
422
|
const wireProps = wiring?.props[alias] || wiring?.props[patternId] || null;
|
|
@@ -426,27 +444,32 @@ function buildPageIR(page, resolvedPatterns, wiring, theme, density, layer) {
|
|
|
426
444
|
const resolved = resolvedPatterns.get(alias) || resolvedPatterns.get(item.pattern);
|
|
427
445
|
children.push(buildPatternNode(item.pattern, alias, resolved, wiring, theme, density, layer));
|
|
428
446
|
} else if (isColumnLayout2(item)) {
|
|
429
|
-
const
|
|
447
|
+
const colEntries = item.cols.map((col) => ({
|
|
448
|
+
id: typeof col === "string" ? col : col.pattern,
|
|
449
|
+
alias: typeof col === "string" ? col : col.as ?? col.pattern
|
|
450
|
+
}));
|
|
430
451
|
const breakpoint = item.at || null;
|
|
431
452
|
const spans = item.span || null;
|
|
432
453
|
let normalizedSpans = null;
|
|
433
454
|
if (spans) {
|
|
434
455
|
normalizedSpans = {};
|
|
435
|
-
for (const
|
|
436
|
-
normalizedSpans[
|
|
456
|
+
for (const entry of colEntries) {
|
|
457
|
+
normalizedSpans[entry.id] = spans[entry.id] || spans[entry.alias] || 1;
|
|
437
458
|
}
|
|
438
459
|
}
|
|
439
460
|
const gridChildren = [];
|
|
440
|
-
for (const
|
|
441
|
-
const resolved = resolvedPatterns.get(
|
|
442
|
-
gridChildren.push(
|
|
461
|
+
for (const entry of colEntries) {
|
|
462
|
+
const resolved = resolvedPatterns.get(entry.alias) || resolvedPatterns.get(entry.id);
|
|
463
|
+
gridChildren.push(
|
|
464
|
+
buildPatternNode(entry.id, entry.alias, resolved, wiring, theme, density, layer)
|
|
465
|
+
);
|
|
443
466
|
}
|
|
444
|
-
const totalCols = normalizedSpans ? Object.values(normalizedSpans).reduce((a, b) => a + b, 0) :
|
|
467
|
+
const totalCols = normalizedSpans ? Object.values(normalizedSpans).reduce((a, b) => a + b, 0) : colEntries.length;
|
|
445
468
|
const breakpoints = item.breakpoints?.map((bp) => ({ at: bp.at, cols: bp.cols })) || null;
|
|
446
469
|
const responsive = item.responsive || null;
|
|
447
470
|
const gridNode = {
|
|
448
471
|
type: "grid",
|
|
449
|
-
id: `grid-${
|
|
472
|
+
id: `grid-${colEntries.map((e) => e.id).join("-")}`,
|
|
450
473
|
children: gridChildren,
|
|
451
474
|
cols: totalCols,
|
|
452
475
|
spans: normalizedSpans,
|
|
@@ -460,7 +483,7 @@ function buildPageIR(page, resolvedPatterns, wiring, theme, density, layer) {
|
|
|
460
483
|
}
|
|
461
484
|
}
|
|
462
485
|
const gapAtom = density.gap.startsWith("_") ? density.gap : density.gap.startsWith("gap") ? `_${density.gap}` : `_gap${density.gap}`;
|
|
463
|
-
const surface = page.surface || `_flex _col ${gapAtom}
|
|
486
|
+
const surface = page.surface || `_flex _col ${gapAtom}`;
|
|
464
487
|
return {
|
|
465
488
|
type: "page",
|
|
466
489
|
id: page.id,
|
|
@@ -472,12 +495,63 @@ function buildPageIR(page, resolvedPatterns, wiring, theme, density, layer) {
|
|
|
472
495
|
};
|
|
473
496
|
}
|
|
474
497
|
|
|
498
|
+
// src/ir-helpers.ts
|
|
499
|
+
function walkIR(node, visitor, parent = null) {
|
|
500
|
+
visitor(node, parent);
|
|
501
|
+
for (const child of node.children) {
|
|
502
|
+
walkIR(child, visitor, node);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function findNodes(root, type) {
|
|
506
|
+
const results = [];
|
|
507
|
+
walkIR(root, (node) => {
|
|
508
|
+
if (node.type === type) {
|
|
509
|
+
results.push(node);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
return results;
|
|
513
|
+
}
|
|
514
|
+
function countPatterns(root) {
|
|
515
|
+
return findNodes(root, "pattern").length;
|
|
516
|
+
}
|
|
517
|
+
function validateIR(root) {
|
|
518
|
+
const errors = [];
|
|
519
|
+
walkIR(root, (node, parent) => {
|
|
520
|
+
if (node.type === "grid") {
|
|
521
|
+
const grid = node;
|
|
522
|
+
if (grid.children.length === 0) {
|
|
523
|
+
errors.push(`Grid node "${grid.id}" has no children`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (node.type === "pattern") {
|
|
527
|
+
const pattern = node;
|
|
528
|
+
if (!pattern.pattern) {
|
|
529
|
+
errors.push(`Pattern node "${pattern.id}" is missing pattern meta`);
|
|
530
|
+
}
|
|
531
|
+
if (!pattern.pattern.patternId) {
|
|
532
|
+
errors.push(`Pattern node "${pattern.id}" has no patternId`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (node.type === "page") {
|
|
536
|
+
if (!node.id) {
|
|
537
|
+
errors.push("Page node is missing id");
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
return errors;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/packs.ts
|
|
545
|
+
import { isV3 as isV33, migrateV2ToV3 as migrateV2ToV32 } from "@decantr/essence-spec";
|
|
546
|
+
|
|
475
547
|
// src/pipeline.ts
|
|
548
|
+
import { isV3 as isV32, migrateV2ToV3, validateEssence } from "@decantr/essence-spec";
|
|
549
|
+
import { createResolver } from "@decantr/registry";
|
|
476
550
|
function extractRouting(essence) {
|
|
477
551
|
if (isV32(essence)) {
|
|
478
|
-
return essence.meta.platform.routing || "
|
|
552
|
+
return essence.meta.platform.routing || "history";
|
|
479
553
|
}
|
|
480
|
-
return essence.platform?.routing || "
|
|
554
|
+
return essence.platform?.routing || "history";
|
|
481
555
|
}
|
|
482
556
|
async function runPipeline(essence, options) {
|
|
483
557
|
const validation = validateEssence(essence);
|
|
@@ -538,57 +612,10 @@ async function runPipeline(essence, options) {
|
|
|
538
612
|
store: storeNode,
|
|
539
613
|
features: resolved.features
|
|
540
614
|
};
|
|
541
|
-
return { ir: appNode };
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// src/ir-helpers.ts
|
|
545
|
-
function walkIR(node, visitor, parent = null) {
|
|
546
|
-
visitor(node, parent);
|
|
547
|
-
for (const child of node.children) {
|
|
548
|
-
walkIR(child, visitor, node);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
function findNodes(root, type) {
|
|
552
|
-
const results = [];
|
|
553
|
-
walkIR(root, (node) => {
|
|
554
|
-
if (node.type === type) {
|
|
555
|
-
results.push(node);
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
return results;
|
|
559
|
-
}
|
|
560
|
-
function countPatterns(root) {
|
|
561
|
-
return findNodes(root, "pattern").length;
|
|
562
|
-
}
|
|
563
|
-
function validateIR(root) {
|
|
564
|
-
const errors = [];
|
|
565
|
-
walkIR(root, (node, parent) => {
|
|
566
|
-
if (node.type === "grid") {
|
|
567
|
-
const grid = node;
|
|
568
|
-
if (grid.children.length === 0) {
|
|
569
|
-
errors.push(`Grid node "${grid.id}" has no children`);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (node.type === "pattern") {
|
|
573
|
-
const pattern = node;
|
|
574
|
-
if (!pattern.pattern) {
|
|
575
|
-
errors.push(`Pattern node "${pattern.id}" is missing pattern meta`);
|
|
576
|
-
}
|
|
577
|
-
if (!pattern.pattern.patternId) {
|
|
578
|
-
errors.push(`Pattern node "${pattern.id}" has no patternId`);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
if (node.type === "page") {
|
|
582
|
-
if (!node.id) {
|
|
583
|
-
errors.push("Page node is missing id");
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
});
|
|
587
|
-
return errors;
|
|
615
|
+
return { ir: appNode, registryTheme: resolved.registryTheme };
|
|
588
616
|
}
|
|
589
617
|
|
|
590
618
|
// src/packs.ts
|
|
591
|
-
import { isV3 as isV33, migrateV2ToV3 as migrateV2ToV32 } from "@decantr/essence-spec";
|
|
592
619
|
var EXECUTION_PACK_SCHEMA_URLS = {
|
|
593
620
|
scaffold: "https://decantr.ai/schemas/scaffold-pack.v1.json",
|
|
594
621
|
section: "https://decantr.ai/schemas/section-pack.v1.json",
|
|
@@ -748,12 +775,14 @@ function summarizeRoutes(appNode) {
|
|
|
748
775
|
return appNode.routes.flatMap((route) => {
|
|
749
776
|
const pageNode = findPageNode(appNode, route.pageId);
|
|
750
777
|
if (!pageNode) return [];
|
|
751
|
-
return [
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
778
|
+
return [
|
|
779
|
+
{
|
|
780
|
+
pageId: pageNode.pageId,
|
|
781
|
+
path: route.path,
|
|
782
|
+
patternIds: collectPatternIds(pageNode),
|
|
783
|
+
shell: route.shell
|
|
784
|
+
}
|
|
785
|
+
];
|
|
757
786
|
});
|
|
758
787
|
}
|
|
759
788
|
function summarizeSectionRoutes(appNode, input) {
|
|
@@ -775,7 +804,9 @@ function collectPagePatterns(page) {
|
|
|
775
804
|
id: patternNode.pattern.patternId,
|
|
776
805
|
alias: patternNode.pattern.alias,
|
|
777
806
|
preset: patternNode.pattern.preset,
|
|
778
|
-
layout: patternNode.pattern.layout
|
|
807
|
+
layout: patternNode.pattern.layout,
|
|
808
|
+
...patternNode.pattern.presetDescription ? { presetDescription: patternNode.pattern.presetDescription } : {},
|
|
809
|
+
...patternNode.pattern.interactions && patternNode.pattern.interactions.length > 0 ? { interactions: patternNode.pattern.interactions } : {}
|
|
779
810
|
});
|
|
780
811
|
});
|
|
781
812
|
return patterns;
|
|
@@ -791,43 +822,108 @@ function renderList(title, entries) {
|
|
|
791
822
|
if (entries.length === 0) return [];
|
|
792
823
|
return [title, ...entries.map((entry) => `- ${entry}`), ""];
|
|
793
824
|
}
|
|
825
|
+
function formatHotkeySemantics(semantics) {
|
|
826
|
+
if (!semantics) return "";
|
|
827
|
+
const parts = [];
|
|
828
|
+
if (typeof semantics.chord_window_ms === "number") {
|
|
829
|
+
parts.push(`chord window ${semantics.chord_window_ms}ms`);
|
|
830
|
+
}
|
|
831
|
+
if (semantics.input_guard === true) parts.push("suppress during text-input focus");
|
|
832
|
+
if (semantics.input_guard === false) parts.push("fire even while typing (explicit)");
|
|
833
|
+
if (semantics.modifier_suppression === true) parts.push("ignore when modifier held");
|
|
834
|
+
if (semantics.modifier_suppression === false) parts.push("allow modifier passthrough (explicit)");
|
|
835
|
+
if (semantics.match_case === true) parts.push("case-sensitive");
|
|
836
|
+
return parts.join("; ");
|
|
837
|
+
}
|
|
838
|
+
function routingImplementationHint(routing) {
|
|
839
|
+
switch (routing) {
|
|
840
|
+
case "hash":
|
|
841
|
+
return "HashRouter from react-router-dom; URLs prefixed with /# (e.g. /#/login). Only for static-only hosts without SPA fallback.";
|
|
842
|
+
case "history":
|
|
843
|
+
return "BrowserRouter from react-router-dom; regular URLs (e.g. /login). Works on Vite dev, Vercel, Netlify, Cloudflare Pages.";
|
|
844
|
+
case "pathname":
|
|
845
|
+
return "pathname-based routing (Next.js App Router file conventions).";
|
|
846
|
+
default:
|
|
847
|
+
return String(routing);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
794
850
|
function renderExecutionPackMarkdown(pack) {
|
|
795
851
|
const lines = [];
|
|
796
852
|
lines.push(`# ${pack.packType.charAt(0).toUpperCase()}${pack.packType.slice(1)} Pack`);
|
|
797
853
|
lines.push("");
|
|
798
854
|
lines.push(`**Objective:** ${pack.objective}`);
|
|
799
|
-
lines.push(
|
|
800
|
-
|
|
855
|
+
lines.push(
|
|
856
|
+
`**Target:** ${pack.target.adapter}${pack.target.framework ? ` (${pack.target.framework})` : ""}`
|
|
857
|
+
);
|
|
858
|
+
lines.push(
|
|
859
|
+
`**Scope:** pages=${pack.scope.pageIds.join(", ") || "none"} | patterns=${pack.scope.patternIds.join(", ") || "none"}`
|
|
860
|
+
);
|
|
801
861
|
lines.push("");
|
|
802
862
|
if (pack.packType === "scaffold") {
|
|
803
863
|
const scaffoldPack = pack;
|
|
804
|
-
const scaffoldShells = [
|
|
864
|
+
const scaffoldShells = [
|
|
865
|
+
...new Set(scaffoldPack.data.routes.map((route) => route.shell).filter(Boolean))
|
|
866
|
+
];
|
|
805
867
|
lines.push("## Scaffold Contract");
|
|
806
868
|
lines.push(`- Shell: ${scaffoldPack.data.shell}`);
|
|
807
869
|
if (scaffoldShells.length > 1) {
|
|
808
870
|
const secondaryShells = scaffoldShells.filter((shell) => shell !== scaffoldPack.data.shell);
|
|
809
|
-
lines.push(
|
|
871
|
+
lines.push(
|
|
872
|
+
`- Shells: ${[`${scaffoldPack.data.shell} (primary)`, ...secondaryShells].join(", ")}`
|
|
873
|
+
);
|
|
810
874
|
}
|
|
811
875
|
lines.push(`- Theme: ${scaffoldPack.data.theme.id} (${scaffoldPack.data.theme.mode})`);
|
|
812
|
-
lines.push(
|
|
876
|
+
lines.push(
|
|
877
|
+
`- Routing: ${scaffoldPack.data.routing} \u2192 ${routingImplementationHint(scaffoldPack.data.routing)}`
|
|
878
|
+
);
|
|
813
879
|
if (scaffoldPack.data.features.length > 0) {
|
|
814
880
|
lines.push(`- Features: ${scaffoldPack.data.features.join(", ")}`);
|
|
815
881
|
}
|
|
816
882
|
if (scaffoldPack.data.navigation?.commandPalette || scaffoldPack.data.navigation?.hotkeys.length) {
|
|
817
883
|
lines.push("- Navigation:");
|
|
818
|
-
|
|
819
|
-
|
|
884
|
+
const cp = scaffoldPack.data.navigation.commandPalette;
|
|
885
|
+
if (cp) {
|
|
886
|
+
if (typeof cp === "object") {
|
|
887
|
+
lines.push(" - Command palette:");
|
|
888
|
+
if (cp.trigger) lines.push(` - Trigger: ${cp.trigger}`);
|
|
889
|
+
if (cp.styling)
|
|
890
|
+
lines.push(` - Styling: ${cp.styling}${cp.width ? ` (width ${cp.width})` : ""}`);
|
|
891
|
+
else if (cp.width) lines.push(` - Width: ${cp.width}`);
|
|
892
|
+
if (cp.placeholder) lines.push(` - Placeholder: "${cp.placeholder}"`);
|
|
893
|
+
if (cp.commands && cp.commands.length > 0) {
|
|
894
|
+
lines.push(` - Commands (${cp.commands.length}):`);
|
|
895
|
+
for (const command of cp.commands) {
|
|
896
|
+
const parts = [];
|
|
897
|
+
if (command.section) parts.push(command.section);
|
|
898
|
+
parts.push(command.label);
|
|
899
|
+
if (command.hotkey) parts.push(`[${command.hotkey}]`);
|
|
900
|
+
if (command.route) parts.push(`\u2192 ${command.route}`);
|
|
901
|
+
lines.push(` - ${command.id}: ${parts.join(" \xB7 ")}`);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
lines.push(" - command palette required");
|
|
906
|
+
}
|
|
820
907
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
908
|
+
const globalSemantics = scaffoldPack.data.navigation.hotkeySemantics;
|
|
909
|
+
if (scaffoldPack.data.navigation.hotkeys.length > 0) {
|
|
910
|
+
const semanticsSummary = formatHotkeySemantics(globalSemantics);
|
|
911
|
+
lines.push(` - Hotkeys${semanticsSummary ? ` (${semanticsSummary})` : ""}:`);
|
|
912
|
+
for (const hotkey of scaffoldPack.data.navigation.hotkeys) {
|
|
913
|
+
const target = [hotkey.label, hotkey.route].filter(Boolean).join(" \u2014 ");
|
|
914
|
+
const perKeySemantics = formatHotkeySemantics(hotkey.semantics);
|
|
915
|
+
const suffix = perKeySemantics ? ` _(${perKeySemantics})_` : "";
|
|
916
|
+
lines.push(` - ${hotkey.key}${target ? `: ${target}` : ""}${suffix}`);
|
|
917
|
+
}
|
|
824
918
|
}
|
|
825
919
|
}
|
|
826
920
|
lines.push("");
|
|
827
921
|
lines.push("## Route Plan");
|
|
828
922
|
for (const route of scaffoldPack.data.routes) {
|
|
829
923
|
const patterns = route.patternIds.length > 0 ? route.patternIds.join(", ") : "none";
|
|
830
|
-
lines.push(
|
|
924
|
+
lines.push(
|
|
925
|
+
`- ${route.path} -> ${route.pageId}${route.shell ? ` @ ${route.shell}` : ""} [${patterns}]`
|
|
926
|
+
);
|
|
831
927
|
}
|
|
832
928
|
lines.push("");
|
|
833
929
|
}
|
|
@@ -848,9 +944,57 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
848
944
|
lines.push("## Section Routes");
|
|
849
945
|
for (const route of sectionPack.data.routes) {
|
|
850
946
|
const patterns = route.patternIds.length > 0 ? route.patternIds.join(", ") : "none";
|
|
851
|
-
lines.push(
|
|
947
|
+
lines.push(
|
|
948
|
+
`- ${route.path} -> ${route.pageId}${route.shell ? ` @ ${route.shell}` : ""} [${patterns}]`
|
|
949
|
+
);
|
|
852
950
|
}
|
|
853
951
|
lines.push("");
|
|
952
|
+
if (sectionPack.data.navigationItems && sectionPack.data.navigationItems.length > 0) {
|
|
953
|
+
lines.push("## Section Navigation");
|
|
954
|
+
lines.push("");
|
|
955
|
+
lines.push(
|
|
956
|
+
"Render these items in the shell's primary navigation. Exact match on label, route, and icon."
|
|
957
|
+
);
|
|
958
|
+
lines.push("");
|
|
959
|
+
for (const item of sectionPack.data.navigationItems) {
|
|
960
|
+
const parts = [`${item.label} \u2192 ${item.route}`];
|
|
961
|
+
if (item.icon) parts.push(`icon: ${item.icon}`);
|
|
962
|
+
if (item.hotkey) parts.push(`hotkey: ${item.hotkey}`);
|
|
963
|
+
if (item.badge) parts.push(`badge: ${item.badge}`);
|
|
964
|
+
if (item.active_match) parts.push(`active match: \`${item.active_match}\``);
|
|
965
|
+
lines.push(`- ${parts.join(" \xB7 ")}`);
|
|
966
|
+
}
|
|
967
|
+
lines.push("");
|
|
968
|
+
}
|
|
969
|
+
if (sectionPack.data.directives && sectionPack.data.directives.length > 0) {
|
|
970
|
+
lines.push("## Section Directives");
|
|
971
|
+
lines.push("");
|
|
972
|
+
lines.push(
|
|
973
|
+
"Execution-level rules every page in this section must obey. Follow exactly \u2014 these live in the pack contract, not narrative prose."
|
|
974
|
+
);
|
|
975
|
+
lines.push("");
|
|
976
|
+
for (const directive of sectionPack.data.directives) {
|
|
977
|
+
lines.push(`- ${directive}`);
|
|
978
|
+
}
|
|
979
|
+
lines.push("");
|
|
980
|
+
}
|
|
981
|
+
if (sectionPack.data.themeDecorators && sectionPack.data.themeDecorators.length > 0) {
|
|
982
|
+
const escCell = (s) => s.replace(/\|/g, "\\|");
|
|
983
|
+
lines.push(`## Required Theme Decorators (${sectionPack.data.theme.id})`);
|
|
984
|
+
lines.push("");
|
|
985
|
+
lines.push(
|
|
986
|
+
`These classes carry the active theme's visual identity. Tokens alone give bones; decorators give personality. Generated source MUST apply these \u2014 without them, the page reads as "themed colors only" with no theme character.`
|
|
987
|
+
);
|
|
988
|
+
lines.push("");
|
|
989
|
+
lines.push("| Class | Intent | Apply to |");
|
|
990
|
+
lines.push("|-------|--------|----------|");
|
|
991
|
+
for (const entry of sectionPack.data.themeDecorators) {
|
|
992
|
+
lines.push(
|
|
993
|
+
`| \`.${entry.class}\` | ${escCell(entry.intent)} | ${escCell(entry.applyTo)} |`
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
lines.push("");
|
|
997
|
+
}
|
|
854
998
|
}
|
|
855
999
|
if (pack.packType === "page") {
|
|
856
1000
|
const pagePack = pack;
|
|
@@ -872,7 +1016,18 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
872
1016
|
lines.push("");
|
|
873
1017
|
lines.push("## Page Patterns");
|
|
874
1018
|
for (const pattern of pagePack.data.patterns) {
|
|
875
|
-
lines.push(
|
|
1019
|
+
lines.push(
|
|
1020
|
+
`- ${pattern.alias} -> ${pattern.id} [${pattern.layout}${pattern.preset ? ` | ${pattern.preset}` : ""}]`
|
|
1021
|
+
);
|
|
1022
|
+
if (pattern.presetDescription) {
|
|
1023
|
+
lines.push(` > ${pattern.presetDescription}`);
|
|
1024
|
+
}
|
|
1025
|
+
if (pattern.interactions && pattern.interactions.length > 0) {
|
|
1026
|
+
lines.push(` **Interactions (MUST implement each \u2014 see DECANTR.md "Interaction Requirements"):**`);
|
|
1027
|
+
for (const interaction of pattern.interactions) {
|
|
1028
|
+
lines.push(` - [ ] ${interaction}`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
876
1031
|
}
|
|
877
1032
|
lines.push("");
|
|
878
1033
|
if (pagePack.data.wiringSignals.length > 0) {
|
|
@@ -882,6 +1037,16 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
882
1037
|
}
|
|
883
1038
|
lines.push("");
|
|
884
1039
|
}
|
|
1040
|
+
if (pagePack.data.directives && pagePack.data.directives.length > 0) {
|
|
1041
|
+
lines.push("## Page Directives");
|
|
1042
|
+
lines.push("");
|
|
1043
|
+
lines.push("Execution-level rules for this route. Follow exactly.");
|
|
1044
|
+
lines.push("");
|
|
1045
|
+
for (const directive of pagePack.data.directives) {
|
|
1046
|
+
lines.push(`- ${directive}`);
|
|
1047
|
+
}
|
|
1048
|
+
lines.push("");
|
|
1049
|
+
}
|
|
885
1050
|
}
|
|
886
1051
|
if (pack.packType === "mutation") {
|
|
887
1052
|
const mutationPack = pack;
|
|
@@ -889,7 +1054,9 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
889
1054
|
lines.push(`- Operation: ${mutationPack.data.mutationType}`);
|
|
890
1055
|
lines.push(`- Shell: ${mutationPack.data.shell}`);
|
|
891
1056
|
lines.push(`- Theme: ${mutationPack.data.theme.id} (${mutationPack.data.theme.mode})`);
|
|
892
|
-
lines.push(
|
|
1057
|
+
lines.push(
|
|
1058
|
+
`- Routing: ${mutationPack.data.routing} \u2192 ${routingImplementationHint(mutationPack.data.routing)}`
|
|
1059
|
+
);
|
|
893
1060
|
if (mutationPack.data.features.length > 0) {
|
|
894
1061
|
lines.push(`- Features: ${mutationPack.data.features.join(", ")}`);
|
|
895
1062
|
}
|
|
@@ -897,7 +1064,9 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
897
1064
|
lines.push("## Route Topology");
|
|
898
1065
|
for (const route of mutationPack.data.routes) {
|
|
899
1066
|
const patterns = route.patternIds.length > 0 ? route.patternIds.join(", ") : "none";
|
|
900
|
-
lines.push(
|
|
1067
|
+
lines.push(
|
|
1068
|
+
`- ${route.path} -> ${route.pageId}${route.shell ? ` @ ${route.shell}` : ""} [${patterns}]`
|
|
1069
|
+
);
|
|
901
1070
|
}
|
|
902
1071
|
lines.push("");
|
|
903
1072
|
if (mutationPack.data.workflow.length > 0) {
|
|
@@ -922,7 +1091,9 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
922
1091
|
lines.push("## Review Topology");
|
|
923
1092
|
for (const route of reviewPack.data.routes) {
|
|
924
1093
|
const patterns = route.patternIds.length > 0 ? route.patternIds.join(", ") : "none";
|
|
925
|
-
lines.push(
|
|
1094
|
+
lines.push(
|
|
1095
|
+
`- ${route.path} -> ${route.pageId}${route.shell ? ` @ ${route.shell}` : ""} [${patterns}]`
|
|
1096
|
+
);
|
|
926
1097
|
}
|
|
927
1098
|
lines.push("");
|
|
928
1099
|
if (reviewPack.data.focusAreas.length > 0) {
|
|
@@ -940,6 +1111,14 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
940
1111
|
lines.push("");
|
|
941
1112
|
}
|
|
942
1113
|
}
|
|
1114
|
+
if (pack.packType === "page") {
|
|
1115
|
+
lines.push("## Shared Contract");
|
|
1116
|
+
lines.push(
|
|
1117
|
+
"Required setup, allowed vocabulary, success checks, anti-patterns, and token budget are shared across every page pack. The full list lives in the pack JSON sidecar (`page-<id>-pack.json`) and in the pack-manifest. Refer there instead of re-reading the same boilerplate 16 times."
|
|
1118
|
+
);
|
|
1119
|
+
lines.push("");
|
|
1120
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
1121
|
+
}
|
|
943
1122
|
lines.push("## Required Setup");
|
|
944
1123
|
if (pack.requiredSetup.length === 0) {
|
|
945
1124
|
lines.push("- None declared.");
|
|
@@ -954,9 +1133,24 @@ function renderExecutionPackMarkdown(pack) {
|
|
|
954
1133
|
lines.push(...pack.allowedVocabulary.map((entry) => `- ${entry}`));
|
|
955
1134
|
}
|
|
956
1135
|
lines.push("");
|
|
957
|
-
lines.push(
|
|
958
|
-
|
|
959
|
-
|
|
1136
|
+
lines.push(
|
|
1137
|
+
...renderList(
|
|
1138
|
+
"## Success Checks",
|
|
1139
|
+
pack.successChecks.map((entry) => `${entry.label} [${entry.severity}]`)
|
|
1140
|
+
)
|
|
1141
|
+
);
|
|
1142
|
+
lines.push(
|
|
1143
|
+
...renderList(
|
|
1144
|
+
"## Anti-Patterns",
|
|
1145
|
+
pack.antiPatterns.map((entry) => `${entry.summary}: ${entry.guidance}`)
|
|
1146
|
+
)
|
|
1147
|
+
);
|
|
1148
|
+
lines.push(
|
|
1149
|
+
...renderList(
|
|
1150
|
+
"## Examples",
|
|
1151
|
+
pack.examples.map((entry) => `${entry.label} (${entry.language})`)
|
|
1152
|
+
)
|
|
1153
|
+
);
|
|
960
1154
|
lines.push("## Token Budget");
|
|
961
1155
|
lines.push(`- Target: ${pack.tokenBudget.target}`);
|
|
962
1156
|
lines.push(`- Max: ${pack.tokenBudget.max}`);
|
|
@@ -976,35 +1170,45 @@ function listPackSections(essence) {
|
|
|
976
1170
|
const declaredSections = essence.blueprint.sections;
|
|
977
1171
|
if (declaredSections && declaredSections.length > 0) {
|
|
978
1172
|
const routedSectionPages = new Set(
|
|
979
|
-
Object.values(essence.blueprint.routes ?? {}).map(
|
|
1173
|
+
Object.values(essence.blueprint.routes ?? {}).map(
|
|
1174
|
+
(entry) => `${entry.section}:${entry.page}`
|
|
1175
|
+
)
|
|
980
1176
|
);
|
|
981
1177
|
return declaredSections.map((section) => {
|
|
982
|
-
const pageIds = section.pages.filter(
|
|
1178
|
+
const pageIds = section.pages.filter(
|
|
1179
|
+
(page) => routedSectionPages.size === 0 || routedSectionPages.has(`${section.id}:${page.id}`)
|
|
1180
|
+
).map((page) => page.id);
|
|
983
1181
|
return {
|
|
984
1182
|
id: section.id,
|
|
985
1183
|
role: section.role,
|
|
986
1184
|
shell: section.shell,
|
|
987
1185
|
description: section.description,
|
|
988
1186
|
features: section.features,
|
|
989
|
-
pageIds
|
|
1187
|
+
pageIds,
|
|
1188
|
+
...Array.isArray(section.navigation_items) && section.navigation_items.length > 0 ? { navigationItems: section.navigation_items } : {},
|
|
1189
|
+
...Array.isArray(section.directives) && section.directives.length > 0 ? { directives: section.directives } : {}
|
|
990
1190
|
};
|
|
991
1191
|
}).filter((section) => section.pageIds.length > 0);
|
|
992
1192
|
}
|
|
993
1193
|
const pages = essence.blueprint.pages ?? [{ id: "home", layout: ["hero"] }];
|
|
994
|
-
return [
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1194
|
+
return [
|
|
1195
|
+
{
|
|
1196
|
+
id: essence.meta.archetype || "default",
|
|
1197
|
+
role: "primary",
|
|
1198
|
+
shell: essence.blueprint.shell ?? "sidebar-main",
|
|
1199
|
+
description: `${essence.meta.archetype || "Application"} section`,
|
|
1200
|
+
features: essence.blueprint.features || [],
|
|
1201
|
+
pageIds: pages.map((page) => page.id)
|
|
1202
|
+
}
|
|
1203
|
+
];
|
|
1002
1204
|
}
|
|
1003
1205
|
function listPackPages(essence) {
|
|
1004
1206
|
const declaredSections = essence.blueprint.sections;
|
|
1005
1207
|
if (declaredSections && declaredSections.length > 0) {
|
|
1006
1208
|
const routedSectionPages = new Set(
|
|
1007
|
-
Object.values(essence.blueprint.routes ?? {}).map(
|
|
1209
|
+
Object.values(essence.blueprint.routes ?? {}).map(
|
|
1210
|
+
(entry) => `${entry.section}:${entry.page}`
|
|
1211
|
+
)
|
|
1008
1212
|
);
|
|
1009
1213
|
return declaredSections.flatMap(
|
|
1010
1214
|
(section) => section.pages.map((page) => ({
|
|
@@ -1012,8 +1216,11 @@ function listPackPages(essence) {
|
|
|
1012
1216
|
shell: page.shell_override ?? section.shell,
|
|
1013
1217
|
sectionId: section.id,
|
|
1014
1218
|
sectionRole: section.role,
|
|
1015
|
-
features: section.features
|
|
1016
|
-
|
|
1219
|
+
features: section.features,
|
|
1220
|
+
...Array.isArray(page.directives) && page.directives.length > 0 ? { directives: page.directives } : {}
|
|
1221
|
+
})).filter(
|
|
1222
|
+
(page) => routedSectionPages.size === 0 || routedSectionPages.has(`${page.sectionId}:${page.pageId}`)
|
|
1223
|
+
)
|
|
1017
1224
|
);
|
|
1018
1225
|
}
|
|
1019
1226
|
const pages = essence.blueprint.pages ?? [{ id: "home", layout: ["hero"] }];
|
|
@@ -1048,13 +1255,15 @@ function buildScaffoldPack(appNode, options = {}) {
|
|
|
1048
1255
|
"Treat the declared routes as the topology source of truth.",
|
|
1049
1256
|
"Preserve the resolved theme and shell contract unless the task explicitly mutates them."
|
|
1050
1257
|
],
|
|
1051
|
-
allowedVocabulary: [
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1258
|
+
allowedVocabulary: [
|
|
1259
|
+
.../* @__PURE__ */ new Set([
|
|
1260
|
+
appNode.shell.config.type,
|
|
1261
|
+
appNode.theme.id,
|
|
1262
|
+
appNode.theme.mode,
|
|
1263
|
+
...appNode.features,
|
|
1264
|
+
...scopePatternIds
|
|
1265
|
+
])
|
|
1266
|
+
],
|
|
1058
1267
|
examples: options.examples ?? [],
|
|
1059
1268
|
antiPatterns: options.antiPatterns ?? [],
|
|
1060
1269
|
successChecks: options.successChecks ?? DEFAULT_SUCCESS_CHECKS,
|
|
@@ -1098,15 +1307,17 @@ function buildSectionPack(appNode, input, options = {}) {
|
|
|
1098
1307
|
"Use the declared section routes as the source of truth for this slice of the app.",
|
|
1099
1308
|
"Keep the section shell consistent unless the task explicitly changes the shell contract."
|
|
1100
1309
|
],
|
|
1101
|
-
allowedVocabulary: [
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1310
|
+
allowedVocabulary: [
|
|
1311
|
+
.../* @__PURE__ */ new Set([
|
|
1312
|
+
input.id,
|
|
1313
|
+
input.role,
|
|
1314
|
+
input.shell,
|
|
1315
|
+
appNode.theme.id,
|
|
1316
|
+
appNode.theme.mode,
|
|
1317
|
+
...input.features,
|
|
1318
|
+
...scopePatternIds
|
|
1319
|
+
])
|
|
1320
|
+
],
|
|
1110
1321
|
examples: options.examples ?? [],
|
|
1111
1322
|
antiPatterns: options.antiPatterns ?? [],
|
|
1112
1323
|
successChecks: options.successChecks ?? DEFAULT_SECTION_SUCCESS_CHECKS,
|
|
@@ -1122,7 +1333,10 @@ function buildSectionPack(appNode, input, options = {}) {
|
|
|
1122
1333
|
mode: appNode.theme.mode,
|
|
1123
1334
|
shape: appNode.theme.shape
|
|
1124
1335
|
},
|
|
1125
|
-
routes
|
|
1336
|
+
routes,
|
|
1337
|
+
...input.navigationItems && input.navigationItems.length > 0 ? { navigationItems: input.navigationItems } : {},
|
|
1338
|
+
...input.directives && input.directives.length > 0 ? { directives: input.directives } : {},
|
|
1339
|
+
...options.themeDecorators && options.themeDecorators.length > 0 ? { themeDecorators: options.themeDecorators } : {}
|
|
1126
1340
|
},
|
|
1127
1341
|
renderedMarkdown: ""
|
|
1128
1342
|
};
|
|
@@ -1155,16 +1369,20 @@ function buildPagePack(appNode, input, options = {}) {
|
|
|
1155
1369
|
"Keep the compiled route and shell contract stable for this page.",
|
|
1156
1370
|
"Treat the listed page patterns as the primary structure for this route."
|
|
1157
1371
|
],
|
|
1158
|
-
allowedVocabulary: [
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1372
|
+
allowedVocabulary: [
|
|
1373
|
+
...new Set(
|
|
1374
|
+
[
|
|
1375
|
+
input.pageId,
|
|
1376
|
+
input.shell,
|
|
1377
|
+
input.sectionId ?? "",
|
|
1378
|
+
input.sectionRole ?? "",
|
|
1379
|
+
appNode.theme.id,
|
|
1380
|
+
appNode.theme.mode,
|
|
1381
|
+
...input.features,
|
|
1382
|
+
...patterns.flatMap((pattern) => [pattern.id, pattern.alias, pattern.layout])
|
|
1383
|
+
].filter(Boolean)
|
|
1384
|
+
)
|
|
1385
|
+
],
|
|
1168
1386
|
examples: options.examples ?? [],
|
|
1169
1387
|
antiPatterns: options.antiPatterns ?? [],
|
|
1170
1388
|
successChecks: options.successChecks ?? DEFAULT_PAGE_SUCCESS_CHECKS,
|
|
@@ -1183,7 +1401,8 @@ function buildPagePack(appNode, input, options = {}) {
|
|
|
1183
1401
|
shape: appNode.theme.shape
|
|
1184
1402
|
},
|
|
1185
1403
|
wiringSignals: pageNode.wiring?.signals.map((signal) => signal.name) ?? [],
|
|
1186
|
-
patterns
|
|
1404
|
+
patterns,
|
|
1405
|
+
...input.directives && input.directives.length > 0 ? { directives: input.directives } : {}
|
|
1187
1406
|
},
|
|
1188
1407
|
renderedMarkdown: ""
|
|
1189
1408
|
};
|
|
@@ -1221,14 +1440,16 @@ function buildMutationPack(appNode, options) {
|
|
|
1221
1440
|
"Treat the compiled topology as the source of truth until the essence changes.",
|
|
1222
1441
|
"Refresh Decantr context after structural mutations so downstream tasks read current packs."
|
|
1223
1442
|
],
|
|
1224
|
-
allowedVocabulary: [
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1443
|
+
allowedVocabulary: [
|
|
1444
|
+
.../* @__PURE__ */ new Set([
|
|
1445
|
+
options.mutationType,
|
|
1446
|
+
appNode.shell.config.type,
|
|
1447
|
+
appNode.theme.id,
|
|
1448
|
+
appNode.theme.mode,
|
|
1449
|
+
...appNode.features,
|
|
1450
|
+
...scopePatternIds
|
|
1451
|
+
])
|
|
1452
|
+
],
|
|
1232
1453
|
examples: options.examples ?? [],
|
|
1233
1454
|
antiPatterns: options.antiPatterns ?? [],
|
|
1234
1455
|
successChecks: options.successChecks ?? DEFAULT_MUTATION_SUCCESS_CHECKS[options.mutationType],
|
|
@@ -1286,15 +1507,17 @@ function buildReviewPack(appNode, options = {}) {
|
|
|
1286
1507
|
"Read the compiled scaffold and route packs before reviewing code.",
|
|
1287
1508
|
"Use concrete evidence from the workspace instead of purely stylistic intuition."
|
|
1288
1509
|
],
|
|
1289
|
-
allowedVocabulary: [
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1510
|
+
allowedVocabulary: [
|
|
1511
|
+
.../* @__PURE__ */ new Set([
|
|
1512
|
+
reviewType,
|
|
1513
|
+
appNode.shell.config.type,
|
|
1514
|
+
appNode.theme.id,
|
|
1515
|
+
appNode.theme.mode,
|
|
1516
|
+
...appNode.features,
|
|
1517
|
+
...scopePatternIds,
|
|
1518
|
+
...focusAreas
|
|
1519
|
+
])
|
|
1520
|
+
],
|
|
1298
1521
|
examples: options.examples ?? [],
|
|
1299
1522
|
antiPatterns: options.antiPatterns ?? DEFAULT_REVIEW_ANTI_PATTERNS,
|
|
1300
1523
|
successChecks: options.successChecks ?? DEFAULT_REVIEW_SUCCESS_CHECKS,
|
|
@@ -1331,32 +1554,57 @@ async function compileExecutionPackBundle(essence, options = {}) {
|
|
|
1331
1554
|
overridePaths: options.overridePaths,
|
|
1332
1555
|
resolver: options.resolver
|
|
1333
1556
|
});
|
|
1557
|
+
const navMeta = effectiveEssence.meta.navigation;
|
|
1558
|
+
const commandPaletteValue = typeof navMeta?.command_palette === "object" && navMeta.command_palette !== null ? navMeta.command_palette : Boolean(navMeta?.command_palette);
|
|
1334
1559
|
const scaffold = buildScaffoldPack(pipeline.ir, {
|
|
1335
1560
|
target: sharedTarget,
|
|
1336
1561
|
navigation: {
|
|
1337
|
-
commandPalette:
|
|
1338
|
-
hotkeys: Array.isArray(
|
|
1339
|
-
hotkey
|
|
1340
|
-
|
|
1562
|
+
commandPalette: commandPaletteValue,
|
|
1563
|
+
hotkeys: Array.isArray(navMeta?.hotkeys) ? navMeta.hotkeys.filter(
|
|
1564
|
+
(hotkey) => Boolean(
|
|
1565
|
+
hotkey && typeof hotkey.key === "string" && typeof hotkey.label === "string"
|
|
1566
|
+
)
|
|
1567
|
+
).map((hotkey) => ({
|
|
1341
1568
|
key: hotkey.key,
|
|
1342
1569
|
route: hotkey.route,
|
|
1343
|
-
label: hotkey.label
|
|
1344
|
-
|
|
1570
|
+
label: hotkey.label,
|
|
1571
|
+
...hotkey.semantics ? { semantics: hotkey.semantics } : {}
|
|
1572
|
+
})) : [],
|
|
1573
|
+
...navMeta?.hotkey_semantics ? { hotkeySemantics: navMeta.hotkey_semantics } : {}
|
|
1345
1574
|
}
|
|
1346
1575
|
});
|
|
1347
1576
|
const review = buildReviewPack(pipeline.ir, {
|
|
1348
1577
|
target: sharedTarget
|
|
1349
1578
|
});
|
|
1350
|
-
const
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1579
|
+
const themeDecorators = (() => {
|
|
1580
|
+
const defs = pipeline.registryTheme?.decorator_definitions;
|
|
1581
|
+
if (!defs) return void 0;
|
|
1582
|
+
const entries = [];
|
|
1583
|
+
for (const [name, def] of Object.entries(defs)) {
|
|
1584
|
+
const intent = def.intent || def.description || "";
|
|
1585
|
+
const applyTo = (def.usage || []).join(", ");
|
|
1586
|
+
if (!intent && !applyTo) continue;
|
|
1587
|
+
entries.push({ class: name, intent, applyTo });
|
|
1588
|
+
}
|
|
1589
|
+
return entries.length > 0 ? entries : void 0;
|
|
1590
|
+
})();
|
|
1591
|
+
const sections = listPackSections(effectiveEssence).map(
|
|
1592
|
+
(section) => buildSectionPack(pipeline.ir, section, {
|
|
1593
|
+
target: sharedTarget,
|
|
1594
|
+
...themeDecorators ? { themeDecorators } : {}
|
|
1595
|
+
})
|
|
1596
|
+
);
|
|
1597
|
+
const pages = listPackPages(effectiveEssence).map(
|
|
1598
|
+
(page) => buildPagePack(pipeline.ir, page, {
|
|
1599
|
+
target: sharedTarget
|
|
1600
|
+
})
|
|
1601
|
+
);
|
|
1602
|
+
const mutations = ["add-page", "modify"].map(
|
|
1603
|
+
(mutationType) => buildMutationPack(pipeline.ir, {
|
|
1604
|
+
mutationType,
|
|
1605
|
+
target: sharedTarget
|
|
1606
|
+
})
|
|
1607
|
+
);
|
|
1360
1608
|
const manifest = {
|
|
1361
1609
|
$schema: PACK_MANIFEST_SCHEMA_URL,
|
|
1362
1610
|
version: "1.0.0",
|