@decantr/cli 1.7.4 → 1.7.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/README.md +84 -0
- package/dist/bin.js +3 -2
- package/dist/{chunk-XKXUVNUQ.js → chunk-H4H3IQJK.js} +561 -122
- package/dist/{chunk-Y5C2O7Z7.js → chunk-KAEQTVAM.js} +1249 -360
- package/dist/chunk-KUDAVJOR.js +46 -0
- package/dist/{heal-VYEGIUAS.js → heal-MURR3RVQ.js} +7 -3
- package/dist/index.js +3 -2
- package/dist/{upgrade-GTUGOUSD.js → upgrade-XNUAON3G.js} +9 -13
- package/package.json +12 -6
- package/src/templates/DECANTR.md.template +31 -3
- package/src/templates/essence-summary.md.template +1 -2
- package/src/templates/task-add-page.md.template +3 -3
- package/src/templates/task-modify.md.template +7 -7
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RegistryClient,
|
|
3
|
+
collectPatternIdsFromItems,
|
|
3
4
|
composeArchetypes,
|
|
4
5
|
composeSections,
|
|
5
6
|
deriveTransitions,
|
|
6
7
|
deriveZones,
|
|
7
8
|
generateTopologySection,
|
|
9
|
+
mapRegistryArchetypeToArchetypeData,
|
|
10
|
+
mapRegistryPatternToPatternSpecSummary,
|
|
11
|
+
mapRegistryThemeToThemeData,
|
|
8
12
|
refreshDerivedFiles,
|
|
9
13
|
scaffoldMinimal,
|
|
10
14
|
scaffoldProject,
|
|
11
|
-
syncRegistry
|
|
12
|
-
|
|
15
|
+
syncRegistry,
|
|
16
|
+
writeExecutionPackBundleArtifacts
|
|
17
|
+
} from "./chunk-H4H3IQJK.js";
|
|
18
|
+
import {
|
|
19
|
+
buildGuardRegistryContext
|
|
20
|
+
} from "./chunk-KUDAVJOR.js";
|
|
13
21
|
|
|
14
22
|
// src/index.ts
|
|
15
|
-
import { readFileSync as
|
|
16
|
-
import { join as
|
|
17
|
-
import { fileURLToPath } from "url";
|
|
23
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync13, existsSync as existsSync24, readdirSync as readdirSync6 } from "fs";
|
|
24
|
+
import { basename, join as join24, dirname as dirname2, isAbsolute, resolve as resolve3 } from "path";
|
|
25
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18
26
|
import { validateEssence as validateEssence2, evaluateGuard, isV3 as isV36 } from "@decantr/essence-spec";
|
|
19
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
RegistryAPIClient as RegistryAPIClient3,
|
|
29
|
+
CONTENT_TYPES as GET_CONTENT_TYPES,
|
|
30
|
+
API_CONTENT_TYPES as LIST_CONTENT_TYPES,
|
|
31
|
+
CONTENT_TYPE_TO_API_CONTENT_TYPE as CONTENT_TYPE_TO_API_CONTENT_TYPE3,
|
|
32
|
+
isContentType as isGetContentType,
|
|
33
|
+
isApiContentType,
|
|
34
|
+
isContentIntelligenceSource
|
|
35
|
+
} from "@decantr/registry";
|
|
20
36
|
|
|
21
37
|
// src/detect.ts
|
|
22
38
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -165,10 +181,10 @@ var CYAN = "\x1B[36m";
|
|
|
165
181
|
function ask(question, defaultValue) {
|
|
166
182
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
167
183
|
const prompt = defaultValue ? `${question} ${DIM}(${defaultValue})${RESET}: ` : `${question}: `;
|
|
168
|
-
return new Promise((
|
|
184
|
+
return new Promise((resolve4) => {
|
|
169
185
|
rl.question(prompt, (answer) => {
|
|
170
186
|
rl.close();
|
|
171
|
-
|
|
187
|
+
resolve4(answer.trim() || defaultValue || "");
|
|
172
188
|
});
|
|
173
189
|
});
|
|
174
190
|
}
|
|
@@ -361,7 +377,7 @@ function mergeWithDefaults(flags, detected) {
|
|
|
361
377
|
}
|
|
362
378
|
async function runSimplifiedInit(blueprints) {
|
|
363
379
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
364
|
-
const question = (q) => new Promise((
|
|
380
|
+
const question = (q) => new Promise((resolve4) => rl.question(q, resolve4));
|
|
365
381
|
console.log("\n? What blueprint would you like to scaffold?\n");
|
|
366
382
|
console.log(" 1. Decantr default (recommended)");
|
|
367
383
|
console.log(" 2. Search registry...\n");
|
|
@@ -399,11 +415,12 @@ import { join as join2 } from "path";
|
|
|
399
415
|
// src/theme-templates.ts
|
|
400
416
|
function getThemeSkeleton(id, name) {
|
|
401
417
|
return {
|
|
402
|
-
$schema: "https://decantr.ai/schemas/
|
|
418
|
+
$schema: "https://decantr.ai/schemas/theme.v1.json",
|
|
403
419
|
id,
|
|
404
420
|
name,
|
|
405
|
-
description:
|
|
421
|
+
description: `Custom theme starter for ${name}. Replace the seed palette, personality, and treatments before publishing.`,
|
|
406
422
|
tags: [],
|
|
423
|
+
personality: "",
|
|
407
424
|
seed: {
|
|
408
425
|
primary: "#6366F1",
|
|
409
426
|
secondary: "#8B5CF6",
|
|
@@ -432,10 +449,12 @@ decantr theme create mytheme
|
|
|
432
449
|
|
|
433
450
|
| Field | Required | Description |
|
|
434
451
|
|-------|----------|-------------|
|
|
452
|
+
| $schema | Yes | Must be \`https://decantr.ai/schemas/theme.v1.json\` |
|
|
435
453
|
| id | Yes | Unique identifier (matches filename) |
|
|
436
454
|
| name | Yes | Display name |
|
|
437
|
-
| description |
|
|
455
|
+
| description | Yes | Brief description for humans and LLMs |
|
|
438
456
|
| tags | No | Searchable tags |
|
|
457
|
+
| personality | No | Short visual summary for LLMs |
|
|
439
458
|
| seed | Yes | Core colors: primary, secondary, accent, background |
|
|
440
459
|
| palette | No | Extended color palette |
|
|
441
460
|
| modes | Yes | Supported modes: ["light"], ["dark"], or both |
|
|
@@ -450,7 +469,7 @@ In \`decantr.essence.json\`:
|
|
|
450
469
|
\`\`\`json
|
|
451
470
|
{
|
|
452
471
|
"theme": {
|
|
453
|
-
"
|
|
472
|
+
"id": "custom:mytheme",
|
|
454
473
|
"mode": "dark"
|
|
455
474
|
}
|
|
456
475
|
}
|
|
@@ -473,10 +492,11 @@ decantr get theme auradecantism
|
|
|
473
492
|
}
|
|
474
493
|
|
|
475
494
|
// src/theme-commands.ts
|
|
476
|
-
var REQUIRED_FIELDS = ["id", "name", "seed", "modes", "shapes", "decantr_compat", "source"];
|
|
495
|
+
var REQUIRED_FIELDS = ["$schema", "id", "name", "description", "seed", "modes", "shapes", "decantr_compat", "source"];
|
|
477
496
|
var REQUIRED_SEED = ["primary", "secondary", "accent", "background"];
|
|
478
497
|
var VALID_MODES = ["light", "dark"];
|
|
479
498
|
var VALID_SHAPES = ["sharp", "rounded", "pill"];
|
|
499
|
+
var THEME_SCHEMA_URL = "https://decantr.ai/schemas/theme.v1.json";
|
|
480
500
|
function validateCustomTheme(theme) {
|
|
481
501
|
const errors = [];
|
|
482
502
|
for (const field of REQUIRED_FIELDS) {
|
|
@@ -484,6 +504,15 @@ function validateCustomTheme(theme) {
|
|
|
484
504
|
errors.push(`Missing required field: ${field}`);
|
|
485
505
|
}
|
|
486
506
|
}
|
|
507
|
+
for (const field of ["id", "name", "description"]) {
|
|
508
|
+
const value = theme[field];
|
|
509
|
+
if (value !== void 0 && (typeof value !== "string" || value.trim().length === 0)) {
|
|
510
|
+
errors.push(`Field "${field}" must be a non-empty string`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if ("$schema" in theme && theme.$schema !== THEME_SCHEMA_URL) {
|
|
514
|
+
errors.push(`Invalid $schema "${String(theme.$schema)}" - must be "${THEME_SCHEMA_URL}"`);
|
|
515
|
+
}
|
|
487
516
|
if (theme.seed && typeof theme.seed === "object") {
|
|
488
517
|
const seed = theme.seed;
|
|
489
518
|
for (const color of REQUIRED_SEED) {
|
|
@@ -643,24 +672,21 @@ function getApiKeyOrToken() {
|
|
|
643
672
|
return creds.api_key || creds.access_token || null;
|
|
644
673
|
}
|
|
645
674
|
|
|
675
|
+
// src/index.ts
|
|
676
|
+
import {
|
|
677
|
+
auditProject,
|
|
678
|
+
critiqueFile as critiqueProjectFile
|
|
679
|
+
} from "@decantr/verifier";
|
|
680
|
+
|
|
646
681
|
// src/commands/publish.ts
|
|
647
682
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
648
683
|
import { join as join4 } from "path";
|
|
649
|
-
import {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
shells: "shell"
|
|
656
|
-
};
|
|
657
|
-
var SINGULAR_TO_PLURAL = {
|
|
658
|
-
pattern: "patterns",
|
|
659
|
-
theme: "themes",
|
|
660
|
-
blueprint: "blueprints",
|
|
661
|
-
archetype: "archetypes",
|
|
662
|
-
shell: "shells"
|
|
663
|
-
};
|
|
684
|
+
import {
|
|
685
|
+
RegistryAPIClient,
|
|
686
|
+
RegistryAPIError,
|
|
687
|
+
API_CONTENT_TYPE_TO_CONTENT_TYPE,
|
|
688
|
+
CONTENT_TYPE_TO_API_CONTENT_TYPE
|
|
689
|
+
} from "@decantr/registry";
|
|
664
690
|
async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
665
691
|
const token = getApiKeyOrToken();
|
|
666
692
|
if (!token) {
|
|
@@ -668,8 +694,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
668
694
|
process.exitCode = 1;
|
|
669
695
|
return;
|
|
670
696
|
}
|
|
671
|
-
const singularType =
|
|
672
|
-
const pluralType =
|
|
697
|
+
const singularType = API_CONTENT_TYPE_TO_CONTENT_TYPE[type] || type;
|
|
698
|
+
const pluralType = CONTENT_TYPE_TO_API_CONTENT_TYPE[type] || CONTENT_TYPE_TO_API_CONTENT_TYPE[singularType] || `${type}s`;
|
|
673
699
|
const customPath = join4(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
|
|
674
700
|
if (!existsSync4(customPath)) {
|
|
675
701
|
console.error(`Custom ${singularType} "${name}" not found at ${customPath}`);
|
|
@@ -700,7 +726,18 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
700
726
|
console.log(`Published ${singularType}/${name} to @community`);
|
|
701
727
|
console.log(`Status: ${result.status}`);
|
|
702
728
|
} catch (err) {
|
|
703
|
-
|
|
729
|
+
if (err instanceof RegistryAPIError) {
|
|
730
|
+
console.error(`Failed to publish: ${err.message}`);
|
|
731
|
+
const details = err.details;
|
|
732
|
+
if (Array.isArray(details?.validationErrors) && details.validationErrors.length > 0) {
|
|
733
|
+
console.error("Validation errors:");
|
|
734
|
+
for (const validationError of details.validationErrors) {
|
|
735
|
+
console.error(` - ${String(validationError)}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
} else {
|
|
739
|
+
console.error(`Failed to publish: ${err.message}`);
|
|
740
|
+
}
|
|
704
741
|
process.exitCode = 1;
|
|
705
742
|
}
|
|
706
743
|
}
|
|
@@ -708,33 +745,110 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
708
745
|
// src/commands/create.ts
|
|
709
746
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
710
747
|
import { join as join5 } from "path";
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
748
|
+
import {
|
|
749
|
+
CONTENT_TYPES,
|
|
750
|
+
CONTENT_TYPE_TO_API_CONTENT_TYPE as CONTENT_TYPE_TO_API_CONTENT_TYPE2
|
|
751
|
+
} from "@decantr/registry";
|
|
752
|
+
var PLURAL = CONTENT_TYPE_TO_API_CONTENT_TYPE2;
|
|
753
|
+
var SCHEMA_URLS = {
|
|
754
|
+
pattern: "https://decantr.ai/schemas/pattern.v2.json",
|
|
755
|
+
theme: "https://decantr.ai/schemas/theme.v1.json",
|
|
756
|
+
blueprint: "https://decantr.ai/schemas/blueprint.v1.json",
|
|
757
|
+
archetype: "https://decantr.ai/schemas/archetype.v2.json",
|
|
758
|
+
shell: "https://decantr.ai/schemas/shell.v1.json"
|
|
718
759
|
};
|
|
760
|
+
function humanizeId(id) {
|
|
761
|
+
return id.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
762
|
+
}
|
|
719
763
|
function getSkeleton(type, id, name) {
|
|
720
764
|
const base = {
|
|
765
|
+
$schema: SCHEMA_URLS[type],
|
|
721
766
|
id,
|
|
722
767
|
name,
|
|
723
|
-
|
|
724
|
-
version: "1.0.0",
|
|
725
|
-
source: "custom"
|
|
768
|
+
version: "1.0.0"
|
|
726
769
|
};
|
|
727
770
|
switch (type) {
|
|
728
771
|
case "pattern":
|
|
729
|
-
return {
|
|
772
|
+
return {
|
|
773
|
+
...base,
|
|
774
|
+
description: `Starter pattern for ${name}. Replace the preset layout, slots, and code examples before publishing.`,
|
|
775
|
+
tags: [],
|
|
776
|
+
components: [],
|
|
777
|
+
default_preset: "standard",
|
|
778
|
+
presets: {
|
|
779
|
+
standard: {
|
|
780
|
+
description: "Default starter preset. Replace the layout atoms and slots with the real structure for this pattern.",
|
|
781
|
+
layout: {
|
|
782
|
+
layout: "stack",
|
|
783
|
+
atoms: "_flex _col _gap4"
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
};
|
|
730
788
|
case "theme":
|
|
731
|
-
return
|
|
789
|
+
return getThemeSkeleton(id, name);
|
|
732
790
|
case "blueprint":
|
|
733
|
-
return {
|
|
791
|
+
return {
|
|
792
|
+
...base,
|
|
793
|
+
description: `Starter blueprint for ${name}. Replace the theme, routes, and composed archetypes before publishing.`,
|
|
794
|
+
tags: [],
|
|
795
|
+
compose: ["starter-home"],
|
|
796
|
+
theme: {
|
|
797
|
+
id: "carbon",
|
|
798
|
+
mode: "dark",
|
|
799
|
+
shape: "rounded"
|
|
800
|
+
},
|
|
801
|
+
personality: "Calm, production-ready starter blueprint. Tailor the voice, routes, and composed archetypes to your product.",
|
|
802
|
+
routes: {
|
|
803
|
+
"/": {
|
|
804
|
+
page: "home",
|
|
805
|
+
shell: "top-nav-main",
|
|
806
|
+
archetype: "starter-home"
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
overrides: {
|
|
810
|
+
features_add: [],
|
|
811
|
+
features_remove: [],
|
|
812
|
+
pages: {},
|
|
813
|
+
pages_remove: []
|
|
814
|
+
}
|
|
815
|
+
};
|
|
734
816
|
case "archetype":
|
|
735
|
-
return {
|
|
817
|
+
return {
|
|
818
|
+
...base,
|
|
819
|
+
role: "primary",
|
|
820
|
+
description: `Starter archetype for ${name}. Replace the sample page, pattern layout, and features before publishing.`,
|
|
821
|
+
tags: ["starter"],
|
|
822
|
+
pages: [
|
|
823
|
+
{
|
|
824
|
+
id: "home",
|
|
825
|
+
description: "Starter page for your primary flow.",
|
|
826
|
+
shell: "top-nav-main",
|
|
827
|
+
patterns: [],
|
|
828
|
+
default_layout: []
|
|
829
|
+
}
|
|
830
|
+
],
|
|
831
|
+
features: [],
|
|
832
|
+
suggested_theme: {
|
|
833
|
+
ids: ["carbon"],
|
|
834
|
+
modes: ["dark"],
|
|
835
|
+
shapes: ["rounded"]
|
|
836
|
+
}
|
|
837
|
+
};
|
|
736
838
|
case "shell":
|
|
737
|
-
return {
|
|
839
|
+
return {
|
|
840
|
+
...base,
|
|
841
|
+
description: `Starter shell for ${name}. Replace the regions, layout guidance, and internal structure before publishing.`,
|
|
842
|
+
layout: "stack",
|
|
843
|
+
atoms: "_flex _col _h[100vh]",
|
|
844
|
+
config: {
|
|
845
|
+
regions: ["header", "body"]
|
|
846
|
+
},
|
|
847
|
+
guidance: {
|
|
848
|
+
section_label_treatment: "d-label",
|
|
849
|
+
section_density: "comfortable"
|
|
850
|
+
}
|
|
851
|
+
};
|
|
738
852
|
}
|
|
739
853
|
}
|
|
740
854
|
function cmdCreate(type, name, projectRoot = process.cwd()) {
|
|
@@ -743,7 +857,8 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
|
|
|
743
857
|
process.exitCode = 1;
|
|
744
858
|
return;
|
|
745
859
|
}
|
|
746
|
-
const
|
|
860
|
+
const contentType = type;
|
|
861
|
+
const plural = PLURAL[contentType];
|
|
747
862
|
const customDir = join5(projectRoot, ".decantr", "custom", plural);
|
|
748
863
|
const filePath = join5(customDir, `${name}.json`);
|
|
749
864
|
if (existsSync5(filePath)) {
|
|
@@ -752,7 +867,7 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
|
|
|
752
867
|
return;
|
|
753
868
|
}
|
|
754
869
|
mkdirSync3(customDir, { recursive: true });
|
|
755
|
-
const skeleton = getSkeleton(
|
|
870
|
+
const skeleton = getSkeleton(contentType, name, humanizeId(name));
|
|
756
871
|
writeFileSync3(filePath, JSON.stringify(skeleton, null, 2));
|
|
757
872
|
console.log(`Created ${type} "${name}" at ${filePath}`);
|
|
758
873
|
console.log(`Edit it, then publish with: decantr publish ${type} ${name}`);
|
|
@@ -1059,15 +1174,14 @@ async function cmdAddSection(archetypeId, args, projectRoot = process.cwd()) {
|
|
|
1059
1174
|
process.exitCode = 1;
|
|
1060
1175
|
return;
|
|
1061
1176
|
}
|
|
1062
|
-
const
|
|
1063
|
-
const inner = raw.data ?? raw;
|
|
1177
|
+
const archetype = result.data;
|
|
1064
1178
|
const newSection = {
|
|
1065
|
-
id:
|
|
1066
|
-
role:
|
|
1067
|
-
shell:
|
|
1068
|
-
features:
|
|
1069
|
-
description:
|
|
1070
|
-
pages: (
|
|
1179
|
+
id: archetype.id || archetypeId,
|
|
1180
|
+
role: archetype.role || "auxiliary",
|
|
1181
|
+
shell: archetype.pages?.[0]?.shell || essence.blueprint.shell || "top-nav-main",
|
|
1182
|
+
features: archetype.features || [],
|
|
1183
|
+
description: archetype.description || "",
|
|
1184
|
+
pages: (archetype.pages || []).map((p) => ({
|
|
1071
1185
|
id: p.id,
|
|
1072
1186
|
layout: p.default_layout?.length ? p.default_layout : ["hero"]
|
|
1073
1187
|
}))
|
|
@@ -1332,6 +1446,8 @@ var RED6 = "\x1B[31m";
|
|
|
1332
1446
|
var YELLOW4 = "\x1B[33m";
|
|
1333
1447
|
var DIM7 = "\x1B[2m";
|
|
1334
1448
|
var RESET7 = "\x1B[0m";
|
|
1449
|
+
var VALID_THEME_SHAPES = ["sharp", "rounded", "pill"];
|
|
1450
|
+
var VALID_THEME_MODES = ["light", "dark", "auto"];
|
|
1335
1451
|
async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
1336
1452
|
if (!themeName) {
|
|
1337
1453
|
console.error(`${RED6}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET7}`);
|
|
@@ -1372,10 +1488,18 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
1372
1488
|
mode = args[++i];
|
|
1373
1489
|
}
|
|
1374
1490
|
}
|
|
1375
|
-
|
|
1491
|
+
if (shape && !VALID_THEME_SHAPES.includes(shape)) {
|
|
1492
|
+
console.error(`${RED6}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET7}`);
|
|
1493
|
+
process.exitCode = 1;
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (mode && !VALID_THEME_MODES.includes(mode)) {
|
|
1497
|
+
console.error(`${RED6}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET7}`);
|
|
1498
|
+
process.exitCode = 1;
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const oldThemeId = essence.dna.theme.id;
|
|
1376
1502
|
essence.dna.theme.id = themeName;
|
|
1377
|
-
delete essence.dna.theme.style;
|
|
1378
|
-
delete essence.dna.theme.recipe;
|
|
1379
1503
|
if (shape) {
|
|
1380
1504
|
essence.dna.theme.shape = shape;
|
|
1381
1505
|
}
|
|
@@ -1388,13 +1512,11 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
1388
1512
|
try {
|
|
1389
1513
|
const themeResult = await registryClient.fetchTheme(themeName);
|
|
1390
1514
|
if (themeResult?.data) {
|
|
1391
|
-
|
|
1392
|
-
const inner = raw.data ?? raw;
|
|
1393
|
-
if (inner.radius) {
|
|
1515
|
+
if (themeResult.data.radius) {
|
|
1394
1516
|
essence.dna.radius = {
|
|
1395
1517
|
...essence.dna.radius,
|
|
1396
|
-
philosophy:
|
|
1397
|
-
base:
|
|
1518
|
+
philosophy: themeResult.data.radius.philosophy || essence.dna.radius.philosophy,
|
|
1519
|
+
base: themeResult.data.radius.base ?? essence.dna.radius.base
|
|
1398
1520
|
};
|
|
1399
1521
|
}
|
|
1400
1522
|
}
|
|
@@ -2357,7 +2479,7 @@ async function resolveTheme(intent, registryClient) {
|
|
|
2357
2479
|
}).sort((a, b) => b.score - a.score);
|
|
2358
2480
|
if (scored[0] && scored[0].score > 0) {
|
|
2359
2481
|
const mode2 = intent.themeHints.includes("light") ? "light" : intent.themeHints.includes("dark") ? "dark" : scored[0].modes?.includes("dark") ? "dark" : "light";
|
|
2360
|
-
return {
|
|
2482
|
+
return { id: scored[0].id, mode: mode2 };
|
|
2361
2483
|
}
|
|
2362
2484
|
}
|
|
2363
2485
|
} catch {
|
|
@@ -2365,14 +2487,14 @@ async function resolveTheme(intent, registryClient) {
|
|
|
2365
2487
|
}
|
|
2366
2488
|
let mode = "dark";
|
|
2367
2489
|
if (hints.includes("light")) mode = "light";
|
|
2368
|
-
if (hints.includes("neon") || hints.includes("glass")) return {
|
|
2369
|
-
if (hints.includes("warm") || hints.includes("elegant")) return {
|
|
2370
|
-
if (hints.includes("cool") || hints.includes("minimal")) return {
|
|
2371
|
-
if (hints.includes("brutalist")) return {
|
|
2372
|
-
if (hints.includes("corporate")) return {
|
|
2373
|
-
if (hints.includes("playful")) return {
|
|
2374
|
-
if (hints.includes("retro")) return {
|
|
2375
|
-
return {
|
|
2490
|
+
if (hints.includes("neon") || hints.includes("glass")) return { id: "obsidianite", mode };
|
|
2491
|
+
if (hints.includes("warm") || hints.includes("elegant")) return { id: "aurealis", mode };
|
|
2492
|
+
if (hints.includes("cool") || hints.includes("minimal")) return { id: "glacialis", mode };
|
|
2493
|
+
if (hints.includes("brutalist")) return { id: "ferrocrete", mode };
|
|
2494
|
+
if (hints.includes("corporate")) return { id: "luminarum", mode };
|
|
2495
|
+
if (hints.includes("playful")) return { id: "solstice", mode };
|
|
2496
|
+
if (hints.includes("retro")) return { id: "oxidian", mode };
|
|
2497
|
+
return { id: "luminarum", mode };
|
|
2376
2498
|
}
|
|
2377
2499
|
function buildPersonality(intent) {
|
|
2378
2500
|
if (intent.personalityHints.length > 0) {
|
|
@@ -2464,8 +2586,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2464
2586
|
}
|
|
2465
2587
|
const bpResult = await registryClient.fetchBlueprint(best.id);
|
|
2466
2588
|
if (bpResult) {
|
|
2467
|
-
|
|
2468
|
-
blueprintData = rawBp.data ?? rawBp;
|
|
2589
|
+
blueprintData = bpResult.data;
|
|
2469
2590
|
}
|
|
2470
2591
|
} else {
|
|
2471
2592
|
console.log(dim(" No strong blueprint match found. Using archetype-based scaffold."));
|
|
@@ -2478,7 +2599,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2478
2599
|
const initOptions = {
|
|
2479
2600
|
blueprint: matchedBlueprint,
|
|
2480
2601
|
archetype: intent.archetype || blueprintData?.compose?.[0]?.archetype || blueprintData?.compose?.[0] || "dashboard-analytics",
|
|
2481
|
-
theme: themeResolved.
|
|
2602
|
+
theme: themeResolved.id,
|
|
2482
2603
|
mode: themeResolved.mode,
|
|
2483
2604
|
shape: "rounded",
|
|
2484
2605
|
target: "react",
|
|
@@ -2490,7 +2611,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2490
2611
|
existing: false
|
|
2491
2612
|
};
|
|
2492
2613
|
if (blueprintData) {
|
|
2493
|
-
if (blueprintData.theme?.id
|
|
2614
|
+
if (blueprintData.theme?.id) initOptions.theme = blueprintData.theme.id;
|
|
2494
2615
|
if (blueprintData.theme?.mode) initOptions.mode = blueprintData.theme.mode;
|
|
2495
2616
|
if (blueprintData.theme?.shape) initOptions.shape = blueprintData.theme.shape;
|
|
2496
2617
|
if (blueprintData.personality) {
|
|
@@ -2541,8 +2662,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2541
2662
|
const id = typeof entry === "string" ? entry : entry.archetype;
|
|
2542
2663
|
const result2 = await registryClient.fetchArchetype(id);
|
|
2543
2664
|
if (result2) {
|
|
2544
|
-
|
|
2545
|
-
archetypeMap.set(id, raw.data ?? raw);
|
|
2665
|
+
archetypeMap.set(id, mapRegistryArchetypeToArchetypeData(result2.data));
|
|
2546
2666
|
} else {
|
|
2547
2667
|
archetypeMap.set(id, null);
|
|
2548
2668
|
}
|
|
@@ -2582,9 +2702,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2582
2702
|
if (page.patterns) {
|
|
2583
2703
|
for (const ref of page.patterns) allPatternIds.add(ref.pattern);
|
|
2584
2704
|
}
|
|
2585
|
-
for (const
|
|
2586
|
-
if (typeof item === "string") allPatternIds.add(item);
|
|
2587
|
-
}
|
|
2705
|
+
for (const patternId of collectPatternIdsFromItems(page.layout)) allPatternIds.add(patternId);
|
|
2588
2706
|
}
|
|
2589
2707
|
}
|
|
2590
2708
|
patternSpecs = {};
|
|
@@ -2592,15 +2710,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2592
2710
|
try {
|
|
2593
2711
|
const result2 = await registryClient.fetchPattern(pid);
|
|
2594
2712
|
if (result2) {
|
|
2595
|
-
|
|
2596
|
-
const inner = raw.data ?? raw;
|
|
2597
|
-
const defaultPreset = inner.default_preset || "standard";
|
|
2598
|
-
const preset = inner.presets?.[defaultPreset];
|
|
2599
|
-
patternSpecs[pid] = {
|
|
2600
|
-
description: inner.description || "",
|
|
2601
|
-
components: inner.components || [],
|
|
2602
|
-
slots: preset?.layout?.slots || {}
|
|
2603
|
-
};
|
|
2713
|
+
patternSpecs[pid] = mapRegistryPatternToPatternSpecSummary(result2.data, void 0, false);
|
|
2604
2714
|
}
|
|
2605
2715
|
} catch {
|
|
2606
2716
|
}
|
|
@@ -2610,7 +2720,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2610
2720
|
const arcId = typeof entry === "string" ? entry : entry.archetype;
|
|
2611
2721
|
const archData = archetypeMap.get(arcId);
|
|
2612
2722
|
if (archData) {
|
|
2613
|
-
const explicitRole = typeof entry === "
|
|
2723
|
+
const explicitRole = typeof entry === "string" ? void 0 : entry.role;
|
|
2614
2724
|
zoneInputs.push({
|
|
2615
2725
|
archetypeId: arcId,
|
|
2616
2726
|
role: explicitRole || archData.role || "auxiliary",
|
|
@@ -2647,31 +2757,13 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2647
2757
|
} else if (intent.archetype && apiAvailable) {
|
|
2648
2758
|
const archResult = await registryClient.fetchArchetype(initOptions.archetype);
|
|
2649
2759
|
if (archResult) {
|
|
2650
|
-
|
|
2651
|
-
archetypeData = raw.data ?? raw;
|
|
2760
|
+
archetypeData = mapRegistryArchetypeToArchetypeData(archResult.data);
|
|
2652
2761
|
}
|
|
2653
2762
|
}
|
|
2654
2763
|
if (apiAvailable && initOptions.theme) {
|
|
2655
2764
|
const themeResult = await registryClient.fetchTheme(initOptions.theme);
|
|
2656
2765
|
if (themeResult) {
|
|
2657
|
-
|
|
2658
|
-
const theme = rawTheme.data ?? rawTheme;
|
|
2659
|
-
themeData = {
|
|
2660
|
-
seed: theme.seed,
|
|
2661
|
-
palette: theme.palette,
|
|
2662
|
-
tokens: theme.tokens,
|
|
2663
|
-
cvd_support: theme.cvd_support,
|
|
2664
|
-
typography: theme.typography,
|
|
2665
|
-
motion: theme.motion,
|
|
2666
|
-
decorators: theme.decorators,
|
|
2667
|
-
treatments: theme.treatments,
|
|
2668
|
-
spatial: theme.spatial,
|
|
2669
|
-
radius: theme.radius,
|
|
2670
|
-
shell: theme.shell,
|
|
2671
|
-
effects: theme.effects,
|
|
2672
|
-
compositions: theme.compositions,
|
|
2673
|
-
pattern_preferences: theme.pattern_preferences
|
|
2674
|
-
};
|
|
2766
|
+
themeData = mapRegistryThemeToThemeData(themeResult.data);
|
|
2675
2767
|
}
|
|
2676
2768
|
}
|
|
2677
2769
|
const richPersonality = buildRichPersonality(intent, blueprintData, themeData);
|
|
@@ -2733,14 +2825,18 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2733
2825
|
}
|
|
2734
2826
|
console.log(`
|
|
2735
2827
|
${GREEN9}${BOLD4}Quality summary:${RESET9}`);
|
|
2736
|
-
console.log(` Context files: ${sectionCount} sections + scaffold.md + DECANTR.md`);
|
|
2828
|
+
console.log(` Context files: ${sectionCount} sections + page packs + section packs + scaffold-pack.md + scaffold.md + DECANTR.md`);
|
|
2737
2829
|
console.log(` CSS: tokens.css + treatments.css + global.css`);
|
|
2738
2830
|
console.log(` @layer cascade: ${hasLayers ? GREEN9 + "yes" + RESET9 : YELLOW6 + "missing" + RESET9}`);
|
|
2739
2831
|
console.log("");
|
|
2740
2832
|
console.log(`${BOLD4} Ready!${RESET9} Next steps:`);
|
|
2741
|
-
console.log(` 1. Read ${cyan("DECANTR.md")}
|
|
2742
|
-
console.log(` 2. Read ${cyan(".decantr/context/scaffold.md")}
|
|
2743
|
-
console.log(` 3.
|
|
2833
|
+
console.log(` 1. Read ${cyan("DECANTR.md")} for guard rules, CSS approach, and workflow`);
|
|
2834
|
+
console.log(` 2. Read ${cyan(".decantr/context/scaffold-pack.md")} first as the primary compiled contract`);
|
|
2835
|
+
console.log(` 3. Read ${cyan(".decantr/context/scaffold.md")} second for broader topology and voice guidance`);
|
|
2836
|
+
console.log(` 4. Read the matching ${cyan(".decantr/context/section-*-pack.md")} and ${cyan(".decantr/context/section-*.md")} files before section work`);
|
|
2837
|
+
console.log(` 5. Read the matching ${cyan(".decantr/context/page-*-pack.md")} file before route work`);
|
|
2838
|
+
console.log(` 6. Build the shell and route structure first, then implement each page`);
|
|
2839
|
+
console.log(` 7. Run ${cyan("decantr check")} and ${cyan("decantr audit")} before you ship`);
|
|
2744
2840
|
console.log("");
|
|
2745
2841
|
}
|
|
2746
2842
|
|
|
@@ -2951,20 +3047,14 @@ function ensureDir(filePath) {
|
|
|
2951
3047
|
// src/commands/registry-mirror.ts
|
|
2952
3048
|
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
2953
3049
|
import { join as join21 } from "path";
|
|
2954
|
-
import { RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
|
|
3050
|
+
import { RegistryAPIClient as RegistryAPIClient2, API_CONTENT_TYPES } from "@decantr/registry";
|
|
2955
3051
|
var GREEN11 = "\x1B[32m";
|
|
2956
3052
|
var RED9 = "\x1B[31m";
|
|
2957
3053
|
var DIM11 = "\x1B[2m";
|
|
2958
3054
|
var CYAN5 = "\x1B[36m";
|
|
2959
3055
|
var YELLOW7 = "\x1B[33m";
|
|
2960
3056
|
var RESET11 = "\x1B[0m";
|
|
2961
|
-
var ALL_CONTENT_TYPES = [
|
|
2962
|
-
"patterns",
|
|
2963
|
-
"archetypes",
|
|
2964
|
-
"themes",
|
|
2965
|
-
"blueprints",
|
|
2966
|
-
"shells"
|
|
2967
|
-
];
|
|
3057
|
+
var ALL_CONTENT_TYPES = [...API_CONTENT_TYPES];
|
|
2968
3058
|
async function cmdRegistryMirror(projectRoot, options = {}) {
|
|
2969
3059
|
const apiUrl = process.env.DECANTR_API_URL || "https://api.decantr.ai/v1";
|
|
2970
3060
|
const apiClient = new RegistryAPIClient2({
|
|
@@ -3035,9 +3125,58 @@ Mirroring registry content to ${DIM11}.decantr/cache/${RESET11}
|
|
|
3035
3125
|
}
|
|
3036
3126
|
|
|
3037
3127
|
// src/commands/new-project.ts
|
|
3038
|
-
import { existsSync as
|
|
3039
|
-
import { join as
|
|
3128
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
3129
|
+
import { join as join23, resolve as resolve2 } from "path";
|
|
3040
3130
|
import { execSync } from "child_process";
|
|
3131
|
+
import { fileURLToPath } from "url";
|
|
3132
|
+
|
|
3133
|
+
// src/offline-content.ts
|
|
3134
|
+
import { cpSync, existsSync as existsSync22, mkdirSync as mkdirSync7 } from "fs";
|
|
3135
|
+
import { join as join22, resolve } from "path";
|
|
3136
|
+
var CONTENT_TYPES2 = ["archetypes", "blueprints", "patterns", "themes", "shells"];
|
|
3137
|
+
function copyIfExists(source, target) {
|
|
3138
|
+
if (!existsSync22(source)) return false;
|
|
3139
|
+
if (resolve(source) === resolve(target)) return true;
|
|
3140
|
+
cpSync(source, target, { recursive: true });
|
|
3141
|
+
return true;
|
|
3142
|
+
}
|
|
3143
|
+
function hydrateContentRoot(projectDir, contentRoot) {
|
|
3144
|
+
if (!existsSync22(contentRoot)) return false;
|
|
3145
|
+
const customRoot = join22(projectDir, ".decantr", "custom");
|
|
3146
|
+
const cacheRoot = join22(projectDir, ".decantr", "cache", "@official");
|
|
3147
|
+
mkdirSync7(customRoot, { recursive: true });
|
|
3148
|
+
mkdirSync7(cacheRoot, { recursive: true });
|
|
3149
|
+
let copiedAny = false;
|
|
3150
|
+
for (const type of CONTENT_TYPES2) {
|
|
3151
|
+
const sourceDir = join22(contentRoot, type);
|
|
3152
|
+
if (!existsSync22(sourceDir)) continue;
|
|
3153
|
+
cpSync(sourceDir, join22(customRoot, type), { recursive: true });
|
|
3154
|
+
cpSync(sourceDir, join22(cacheRoot, type), { recursive: true });
|
|
3155
|
+
copiedAny = true;
|
|
3156
|
+
}
|
|
3157
|
+
return copiedAny;
|
|
3158
|
+
}
|
|
3159
|
+
function seedOfflineRegistry(projectDir, workspaceRoot) {
|
|
3160
|
+
const projectDecantrRoot = join22(projectDir, ".decantr");
|
|
3161
|
+
mkdirSync7(projectDecantrRoot, { recursive: true });
|
|
3162
|
+
const copiedCache = copyIfExists(join22(workspaceRoot, ".decantr", "cache"), join22(projectDecantrRoot, "cache"));
|
|
3163
|
+
const copiedCustom = copyIfExists(join22(workspaceRoot, ".decantr", "custom"), join22(projectDecantrRoot, "custom"));
|
|
3164
|
+
if (copiedCache || copiedCustom) {
|
|
3165
|
+
return { seeded: true, strategy: "workspace-cache" };
|
|
3166
|
+
}
|
|
3167
|
+
const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve(process.env.DECANTR_CONTENT_DIR) : null;
|
|
3168
|
+
const siblingContentRoot = resolve(workspaceRoot, "..", "decantr-content");
|
|
3169
|
+
const contentRoot = configuredContentRoot && existsSync22(configuredContentRoot) ? configuredContentRoot : siblingContentRoot;
|
|
3170
|
+
if (hydrateContentRoot(projectDir, contentRoot)) {
|
|
3171
|
+
return {
|
|
3172
|
+
seeded: true,
|
|
3173
|
+
strategy: configuredContentRoot && existsSync22(configuredContentRoot) ? "configured-content-root" : "sibling-content-root"
|
|
3174
|
+
};
|
|
3175
|
+
}
|
|
3176
|
+
return { seeded: false, strategy: null };
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3179
|
+
// src/commands/new-project.ts
|
|
3041
3180
|
var BOLD5 = "\x1B[1m";
|
|
3042
3181
|
var DIM12 = "\x1B[2m";
|
|
3043
3182
|
var RESET12 = "\x1B[0m";
|
|
@@ -3062,20 +3201,92 @@ function dim2(text) {
|
|
|
3062
3201
|
function cyan2(text) {
|
|
3063
3202
|
return `${CYAN6}${text}${RESET12}`;
|
|
3064
3203
|
}
|
|
3204
|
+
function detectRoutingMode(projectDir) {
|
|
3205
|
+
try {
|
|
3206
|
+
const essence = JSON.parse(readFileSync15(join23(projectDir, "decantr.essence.json"), "utf-8"));
|
|
3207
|
+
const routing = essence.meta?.platform?.routing;
|
|
3208
|
+
if (routing === "history" || routing === "pathname") {
|
|
3209
|
+
return routing;
|
|
3210
|
+
}
|
|
3211
|
+
return "hash";
|
|
3212
|
+
} catch {
|
|
3213
|
+
return "hash";
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
function writeStarterRuntimeFiles(projectDir, title, routingMode) {
|
|
3217
|
+
const srcDir = join23(projectDir, "src");
|
|
3218
|
+
const routerImport = routingMode === "hash" ? "HashRouter" : "BrowserRouter";
|
|
3219
|
+
const mainTsx = `import { StrictMode } from 'react';
|
|
3220
|
+
import { createRoot } from 'react-dom/client';
|
|
3221
|
+
import { ${routerImport} } from 'react-router-dom';
|
|
3222
|
+
import { App } from './App';
|
|
3223
|
+
import './styles/global.css';
|
|
3224
|
+
import './styles/tokens.css';
|
|
3225
|
+
import './styles/treatments.css';
|
|
3226
|
+
|
|
3227
|
+
createRoot(document.getElementById('root')!).render(
|
|
3228
|
+
<StrictMode>
|
|
3229
|
+
<${routerImport}>
|
|
3230
|
+
<App />
|
|
3231
|
+
</${routerImport}>
|
|
3232
|
+
</StrictMode>,
|
|
3233
|
+
);
|
|
3234
|
+
`;
|
|
3235
|
+
writeFileSync12(join23(srcDir, "main.tsx"), mainTsx);
|
|
3236
|
+
const appTsx = `import { css } from '@decantr/css';
|
|
3237
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3238
|
+
|
|
3239
|
+
function WelcomePage() {
|
|
3240
|
+
return (
|
|
3241
|
+
<>
|
|
3242
|
+
<a href="#main-content" className="skip-link">Skip to content</a>
|
|
3243
|
+
<main id="main-content" className={css('_minh[100vh] _flex _col _aic _jcc _p6 _gap4')}>
|
|
3244
|
+
<section className={css('_wfull _mw[42rem]') + ' d-section'} data-density="comfortable">
|
|
3245
|
+
<div className={css('_flex _col _aic _gap4 _textc') + ' d-surface'} data-elevation="raised">
|
|
3246
|
+
<p className="d-label" data-anchor>Decantr starter</p>
|
|
3247
|
+
<h1 className={css('_heading2')}>${title}</h1>
|
|
3248
|
+
<p className={css('_textsm _fgmuted _mw[32rem]')}>
|
|
3249
|
+
Scaffolded with Decantr. Read DECANTR.md and the compiled packs in .decantr/context before building routes.
|
|
3250
|
+
</p>
|
|
3251
|
+
<div className={css('_flex _gap3 _wrap _jcc')}>
|
|
3252
|
+
<span className="d-annotation" data-status="info">Runtime: @decantr/css</span>
|
|
3253
|
+
<span className="d-annotation" data-status="success">Routing: ${routingMode}</span>
|
|
3254
|
+
</div>
|
|
3255
|
+
</div>
|
|
3256
|
+
</section>
|
|
3257
|
+
</main>
|
|
3258
|
+
</>
|
|
3259
|
+
);
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
export function App() {
|
|
3263
|
+
return (
|
|
3264
|
+
<Routes>
|
|
3265
|
+
<Route path="/" element={<WelcomePage />} />
|
|
3266
|
+
</Routes>
|
|
3267
|
+
);
|
|
3268
|
+
}
|
|
3269
|
+
`;
|
|
3270
|
+
writeFileSync12(join23(srcDir, "App.tsx"), appTsx);
|
|
3271
|
+
}
|
|
3272
|
+
function getTargetRoutingMode(target) {
|
|
3273
|
+
return (target || "react").toLowerCase() === "nextjs" ? "pathname" : "hash";
|
|
3274
|
+
}
|
|
3065
3275
|
async function cmdNewProject(projectName, options) {
|
|
3066
|
-
const
|
|
3276
|
+
const workspaceRoot = process.cwd();
|
|
3277
|
+
const projectDir = resolve2(workspaceRoot, projectName);
|
|
3067
3278
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
|
|
3068
3279
|
console.error(error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores."));
|
|
3069
3280
|
process.exitCode = 1;
|
|
3070
3281
|
return;
|
|
3071
3282
|
}
|
|
3072
|
-
if (
|
|
3283
|
+
if (existsSync23(projectDir)) {
|
|
3073
3284
|
console.error(error2(`Directory "${projectName}" already exists.`));
|
|
3074
3285
|
process.exitCode = 1;
|
|
3075
3286
|
return;
|
|
3076
3287
|
}
|
|
3077
3288
|
console.log(heading(`Creating ${projectName}...`));
|
|
3078
|
-
|
|
3289
|
+
mkdirSync8(projectDir, { recursive: true });
|
|
3079
3290
|
console.log(dim2(` Created ${projectName}/`));
|
|
3080
3291
|
const packageJson = {
|
|
3081
3292
|
name: projectName,
|
|
@@ -3101,7 +3312,7 @@ async function cmdNewProject(projectName, options) {
|
|
|
3101
3312
|
"vite": "^6.0.0"
|
|
3102
3313
|
}
|
|
3103
3314
|
};
|
|
3104
|
-
writeFileSync12(
|
|
3315
|
+
writeFileSync12(join23(projectDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
3105
3316
|
console.log(dim2(" Created package.json"));
|
|
3106
3317
|
const viteConfig = `import { defineConfig } from 'vite';
|
|
3107
3318
|
import react from '@vitejs/plugin-react';
|
|
@@ -3110,7 +3321,7 @@ export default defineConfig({
|
|
|
3110
3321
|
plugins: [react()],
|
|
3111
3322
|
});
|
|
3112
3323
|
`;
|
|
3113
|
-
writeFileSync12(
|
|
3324
|
+
writeFileSync12(join23(projectDir, "vite.config.ts"), viteConfig);
|
|
3114
3325
|
console.log(dim2(" Created vite.config.ts"));
|
|
3115
3326
|
const tsconfig = {
|
|
3116
3327
|
compilerOptions: {
|
|
@@ -3133,7 +3344,7 @@ export default defineConfig({
|
|
|
3133
3344
|
},
|
|
3134
3345
|
include: ["src"]
|
|
3135
3346
|
};
|
|
3136
|
-
writeFileSync12(
|
|
3347
|
+
writeFileSync12(join23(projectDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
|
|
3137
3348
|
const tsconfigApp = {
|
|
3138
3349
|
compilerOptions: {
|
|
3139
3350
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
@@ -3156,7 +3367,7 @@ export default defineConfig({
|
|
|
3156
3367
|
},
|
|
3157
3368
|
include: ["src"]
|
|
3158
3369
|
};
|
|
3159
|
-
writeFileSync12(
|
|
3370
|
+
writeFileSync12(join23(projectDir, "tsconfig.app.json"), JSON.stringify(tsconfigApp, null, 2) + "\n");
|
|
3160
3371
|
console.log(dim2(" Created tsconfig.json"));
|
|
3161
3372
|
const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3162
3373
|
const indexHtml = `<!doctype html>
|
|
@@ -3172,49 +3383,13 @@ export default defineConfig({
|
|
|
3172
3383
|
</body>
|
|
3173
3384
|
</html>
|
|
3174
3385
|
`;
|
|
3175
|
-
writeFileSync12(
|
|
3386
|
+
writeFileSync12(join23(projectDir, "index.html"), indexHtml);
|
|
3176
3387
|
console.log(dim2(" Created index.html"));
|
|
3177
|
-
const srcDir =
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
import { App } from './App';
|
|
3183
|
-
import './styles/tokens.css';
|
|
3184
|
-
import './styles/treatments.css';
|
|
3185
|
-
import './styles/global.css';
|
|
3186
|
-
|
|
3187
|
-
createRoot(document.getElementById('root')!).render(
|
|
3188
|
-
<StrictMode>
|
|
3189
|
-
<BrowserRouter>
|
|
3190
|
-
<App />
|
|
3191
|
-
</BrowserRouter>
|
|
3192
|
-
</StrictMode>,
|
|
3193
|
-
);
|
|
3194
|
-
`;
|
|
3195
|
-
writeFileSync12(join22(srcDir, "main.tsx"), mainTsx);
|
|
3196
|
-
const appTsx = `import { Routes, Route } from 'react-router-dom';
|
|
3197
|
-
|
|
3198
|
-
function WelcomePage() {
|
|
3199
|
-
return (
|
|
3200
|
-
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', gap: '1rem' }}>
|
|
3201
|
-
<h1>${title}</h1>
|
|
3202
|
-
<p style={{ opacity: 0.6 }}>Scaffolded with Decantr. Run <code>decantr status</code> to check project health.</p>
|
|
3203
|
-
</div>
|
|
3204
|
-
);
|
|
3205
|
-
}
|
|
3206
|
-
|
|
3207
|
-
export function App() {
|
|
3208
|
-
return (
|
|
3209
|
-
<Routes>
|
|
3210
|
-
<Route path="/" element={<WelcomePage />} />
|
|
3211
|
-
</Routes>
|
|
3212
|
-
);
|
|
3213
|
-
}
|
|
3214
|
-
`;
|
|
3215
|
-
writeFileSync12(join22(srcDir, "App.tsx"), appTsx);
|
|
3216
|
-
writeFileSync12(join22(srcDir, "vite-env.d.ts"), '/// <reference types="vite/client" />\n');
|
|
3217
|
-
mkdirSync7(join22(srcDir, "styles"), { recursive: true });
|
|
3388
|
+
const srcDir = join23(projectDir, "src");
|
|
3389
|
+
mkdirSync8(srcDir, { recursive: true });
|
|
3390
|
+
writeStarterRuntimeFiles(projectDir, title, getTargetRoutingMode(options.target));
|
|
3391
|
+
writeFileSync12(join23(srcDir, "vite-env.d.ts"), '/// <reference types="vite/client" />\n');
|
|
3392
|
+
mkdirSync8(join23(srcDir, "styles"), { recursive: true });
|
|
3218
3393
|
console.log(dim2(" Created src/"));
|
|
3219
3394
|
console.log(heading("Installing dependencies..."));
|
|
3220
3395
|
const packageManager = detectPackageManager();
|
|
@@ -3224,6 +3399,24 @@ export function App() {
|
|
|
3224
3399
|
console.log(`
|
|
3225
3400
|
${YELLOW8}Dependency install failed. Run \`${packageManager} install\` manually.${RESET12}`);
|
|
3226
3401
|
}
|
|
3402
|
+
const requiresOfflineContent = Boolean(options.offline && (options.blueprint || options.archetype));
|
|
3403
|
+
const seeded = options.offline ? seedOfflineRegistry(projectDir, workspaceRoot) : { seeded: false, strategy: null };
|
|
3404
|
+
if (seeded.seeded) {
|
|
3405
|
+
console.log(dim2(` Seeded offline registry content from ${seeded.strategy}.`));
|
|
3406
|
+
} else if (requiresOfflineContent) {
|
|
3407
|
+
console.log(`${YELLOW8} Offline blueprint/archetype resolution requires local registry content.${RESET12}`);
|
|
3408
|
+
console.log(dim2(" No parent workspace cache/custom content or configured decantr-content source was found."));
|
|
3409
|
+
console.log("");
|
|
3410
|
+
console.log(success2(`
|
|
3411
|
+
\u2713 Project "${projectName}" created!
|
|
3412
|
+
`));
|
|
3413
|
+
console.log(` ${cyan2("cd " + projectName)}`);
|
|
3414
|
+
console.log(` ${cyan2(packageManager + " run dev")}`);
|
|
3415
|
+
console.log(` ${cyan2("decantr sync")} ${dim2("# when online, then rerun decantr init")}`);
|
|
3416
|
+
console.log(` ${cyan2("DECANTR_CONTENT_DIR=/path/to/decantr-content decantr init --existing --offline")} ${dim2("# or seed a local content source")}`);
|
|
3417
|
+
console.log("");
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3227
3420
|
console.log(heading("Initializing Decantr..."));
|
|
3228
3421
|
const initFlags = ["--yes", "--existing"];
|
|
3229
3422
|
if (options.blueprint) initFlags.push(`--blueprint=${options.blueprint}`);
|
|
@@ -3231,12 +3424,15 @@ ${YELLOW8}Dependency install failed. Run \`${packageManager} install\` manually.
|
|
|
3231
3424
|
if (options.theme) initFlags.push(`--theme=${options.theme}`);
|
|
3232
3425
|
if (options.mode) initFlags.push(`--mode=${options.mode}`);
|
|
3233
3426
|
if (options.shape) initFlags.push(`--shape=${options.shape}`);
|
|
3427
|
+
if (options.target) initFlags.push(`--target=${options.target}`);
|
|
3234
3428
|
if (options.offline) initFlags.push("--offline");
|
|
3235
3429
|
if (options.registry) initFlags.push(`--registry=${options.registry}`);
|
|
3236
3430
|
try {
|
|
3237
|
-
const
|
|
3238
|
-
const
|
|
3431
|
+
const bundledCliEntrypoint = fileURLToPath(new URL("./bin.js", import.meta.url));
|
|
3432
|
+
const cliEntrypoint = existsSync23(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync23(process.argv[1]) ? process.argv[1] : null;
|
|
3433
|
+
const cliPath = cliEntrypoint ? `"${process.execPath}" "${cliEntrypoint}"` : "npx decantr";
|
|
3239
3434
|
execSync(`${cliPath} init ${initFlags.join(" ")}`, { cwd: projectDir, stdio: "inherit" });
|
|
3435
|
+
writeStarterRuntimeFiles(projectDir, title, detectRoutingMode(projectDir));
|
|
3240
3436
|
} catch {
|
|
3241
3437
|
console.log(`
|
|
3242
3438
|
${YELLOW8}Decantr init encountered issues. Run \`decantr init\` manually inside ${projectName}/.${RESET12}`);
|
|
@@ -3249,13 +3445,13 @@ ${YELLOW8}Decantr init encountered issues. Run \`decantr init\` manually inside
|
|
|
3249
3445
|
console.log("");
|
|
3250
3446
|
}
|
|
3251
3447
|
function detectPackageManager() {
|
|
3252
|
-
if (
|
|
3448
|
+
if (existsSync23(join23(process.cwd(), "pnpm-lock.yaml")) || existsSync23(join23(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
3253
3449
|
return "pnpm";
|
|
3254
3450
|
}
|
|
3255
|
-
if (
|
|
3451
|
+
if (existsSync23(join23(process.cwd(), "yarn.lock"))) {
|
|
3256
3452
|
return "yarn";
|
|
3257
3453
|
}
|
|
3258
|
-
if (
|
|
3454
|
+
if (existsSync23(join23(process.cwd(), "bun.lockb")) || existsSync23(join23(process.cwd(), "bun.lock"))) {
|
|
3259
3455
|
return "bun";
|
|
3260
3456
|
}
|
|
3261
3457
|
return "npm";
|
|
@@ -3286,6 +3482,64 @@ function dim3(text) {
|
|
|
3286
3482
|
function cyan3(text) {
|
|
3287
3483
|
return `${CYAN7}${text}${RESET13}`;
|
|
3288
3484
|
}
|
|
3485
|
+
function formatIntelligenceSummary(intelligence) {
|
|
3486
|
+
if (!intelligence) {
|
|
3487
|
+
return null;
|
|
3488
|
+
}
|
|
3489
|
+
const parts = [];
|
|
3490
|
+
const recommendationReasons = intelligence.recommendation_reasons ?? [];
|
|
3491
|
+
const recommendationBlockers = intelligence.recommendation_blockers ?? [];
|
|
3492
|
+
if (intelligence.recommended) {
|
|
3493
|
+
parts.push("recommended");
|
|
3494
|
+
}
|
|
3495
|
+
switch (intelligence.source) {
|
|
3496
|
+
case "authored":
|
|
3497
|
+
parts.push("authored intelligence");
|
|
3498
|
+
break;
|
|
3499
|
+
case "hybrid":
|
|
3500
|
+
parts.push("hybrid intelligence");
|
|
3501
|
+
break;
|
|
3502
|
+
case "benchmark":
|
|
3503
|
+
parts.push("benchmark-backed");
|
|
3504
|
+
break;
|
|
3505
|
+
default:
|
|
3506
|
+
break;
|
|
3507
|
+
}
|
|
3508
|
+
switch (intelligence.verification_status) {
|
|
3509
|
+
case "smoke-green":
|
|
3510
|
+
parts.push("smoke verified");
|
|
3511
|
+
break;
|
|
3512
|
+
case "build-green":
|
|
3513
|
+
parts.push("build verified");
|
|
3514
|
+
break;
|
|
3515
|
+
case "smoke-red":
|
|
3516
|
+
parts.push("smoke failed");
|
|
3517
|
+
break;
|
|
3518
|
+
case "build-red":
|
|
3519
|
+
parts.push("build failed");
|
|
3520
|
+
break;
|
|
3521
|
+
default:
|
|
3522
|
+
break;
|
|
3523
|
+
}
|
|
3524
|
+
if (intelligence.confidence_tier === "verified") {
|
|
3525
|
+
parts.push("verified confidence");
|
|
3526
|
+
} else if (intelligence.confidence_tier === "high") {
|
|
3527
|
+
parts.push("high confidence");
|
|
3528
|
+
} else if (intelligence.confidence_tier === "medium") {
|
|
3529
|
+
parts.push("medium confidence");
|
|
3530
|
+
} else if (intelligence.benchmark_confidence !== "none") {
|
|
3531
|
+
parts.push(`${intelligence.benchmark_confidence} confidence`);
|
|
3532
|
+
}
|
|
3533
|
+
if (intelligence.quality_score != null) {
|
|
3534
|
+
parts.push(`quality ${intelligence.quality_score}`);
|
|
3535
|
+
}
|
|
3536
|
+
if (intelligence.recommended && recommendationReasons.length > 0) {
|
|
3537
|
+
parts.push(`because ${recommendationReasons[0]}`);
|
|
3538
|
+
} else if (!intelligence.recommended && recommendationBlockers.length > 0) {
|
|
3539
|
+
parts.push(`held back by ${recommendationBlockers[0]}`);
|
|
3540
|
+
}
|
|
3541
|
+
return parts.length > 0 ? parts.join(" | ") : null;
|
|
3542
|
+
}
|
|
3289
3543
|
function extractPatternName(item) {
|
|
3290
3544
|
if (typeof item === "string") return item;
|
|
3291
3545
|
if (typeof item === "object" && item !== null) {
|
|
@@ -3301,12 +3555,30 @@ function generateCuratedPrompt(ctx) {
|
|
|
3301
3555
|
const lines = [];
|
|
3302
3556
|
lines.push("Build this application using the Decantr design system.");
|
|
3303
3557
|
lines.push("");
|
|
3304
|
-
lines.push("
|
|
3305
|
-
lines.push("
|
|
3306
|
-
lines.push("
|
|
3307
|
-
lines.push("
|
|
3558
|
+
lines.push("Treat the compiled execution-pack files as the primary source of truth.");
|
|
3559
|
+
lines.push("Use narrative docs only as secondary explanation when the compiled packs are not enough.");
|
|
3560
|
+
lines.push("Use only files present in this workspace as the source of truth. If local scaffold files disagree, stop and report the mismatch instead of relying on external Decantr assumptions or prior examples.");
|
|
3561
|
+
lines.push("");
|
|
3562
|
+
lines.push("Read in this order:");
|
|
3563
|
+
lines.push("1. DECANTR.md for the design spec, CSS approach, and guard rules.");
|
|
3564
|
+
lines.push("2. .decantr/context/scaffold-pack.md for the compact compiled shell, theme, feature, and route contract.");
|
|
3565
|
+
lines.push("3. .decantr/context/scaffold.md for the broader app overview, topology, route map, and voice guidance.");
|
|
3566
|
+
lines.push("4. Before working on any section, read its matching .decantr/context/section-*-pack.md and then .decantr/context/section-*.md files.");
|
|
3567
|
+
lines.push("5. Before working on any route/page, read its matching .decantr/context/page-*-pack.md file.");
|
|
3308
3568
|
lines.push("");
|
|
3309
|
-
lines.push("
|
|
3569
|
+
lines.push("Implementation rules:");
|
|
3570
|
+
lines.push("- Do not invent routes, sections, shells, themes, or features that are not present in the compiled packs.");
|
|
3571
|
+
lines.push("- Prefer scaffold-pack, section-pack, and page-pack guidance over broader narrative docs when they differ.");
|
|
3572
|
+
lines.push("- Start with the shell layouts and route structure first, then build section pages route by route.");
|
|
3573
|
+
lines.push("- Import src/styles/global.css, src/styles/tokens.css, and src/styles/treatments.css.");
|
|
3574
|
+
lines.push("- Use the existing Decantr tokens, treatments, and decorators instead of inventing a new visual system.");
|
|
3575
|
+
lines.push("- Do not modify generated context files unless the task is explicitly to regenerate or refresh Decantr context.");
|
|
3576
|
+
lines.push("");
|
|
3577
|
+
lines.push("Execution flow:");
|
|
3578
|
+
lines.push("- Build the shell and shared layout first.");
|
|
3579
|
+
lines.push("- Then implement each section's pages using the matching section and page packs.");
|
|
3580
|
+
lines.push("- After implementation, run decantr check and decantr audit and fix any contract or drift issues.");
|
|
3581
|
+
lines.push("- If a required context file is missing or inconsistent, stop and report exactly which file is missing before continuing.");
|
|
3310
3582
|
return lines.join("\n");
|
|
3311
3583
|
}
|
|
3312
3584
|
function getAPIClient() {
|
|
@@ -3315,10 +3587,448 @@ function getAPIClient() {
|
|
|
3315
3587
|
apiKey: process.env.DECANTR_API_KEY || void 0
|
|
3316
3588
|
});
|
|
3317
3589
|
}
|
|
3318
|
-
|
|
3590
|
+
function getPublicAPIClient() {
|
|
3591
|
+
return new RegistryAPIClient3({
|
|
3592
|
+
baseUrl: process.env.DECANTR_API_URL || void 0
|
|
3593
|
+
});
|
|
3594
|
+
}
|
|
3595
|
+
function resolveUserPath(inputPath, cwd = process.cwd()) {
|
|
3596
|
+
return isAbsolute(inputPath) ? inputPath : resolve3(cwd, inputPath);
|
|
3597
|
+
}
|
|
3598
|
+
function extractHostedAssetPaths(indexHtml) {
|
|
3599
|
+
const assetPaths = /* @__PURE__ */ new Set();
|
|
3600
|
+
for (const match of indexHtml.matchAll(/<(?:script|link)[^>]+(?:src|href)="([^"]+)"/g)) {
|
|
3601
|
+
const assetPath = match[1];
|
|
3602
|
+
const assetsIndex = assetPath.indexOf("/assets/");
|
|
3603
|
+
if (assetsIndex === -1) continue;
|
|
3604
|
+
assetPaths.add(assetPath.slice(assetsIndex));
|
|
3605
|
+
}
|
|
3606
|
+
return [...assetPaths];
|
|
3607
|
+
}
|
|
3608
|
+
function readHostedDistSnapshot(distPath) {
|
|
3609
|
+
const resolvedDistPath = distPath ? resolveUserPath(distPath) : join24(process.cwd(), "dist");
|
|
3610
|
+
const indexPath = join24(resolvedDistPath, "index.html");
|
|
3611
|
+
if (!existsSync24(indexPath)) {
|
|
3612
|
+
return void 0;
|
|
3613
|
+
}
|
|
3614
|
+
const indexHtml = readFileSync16(indexPath, "utf-8");
|
|
3615
|
+
const assetPaths = extractHostedAssetPaths(indexHtml);
|
|
3616
|
+
const assets = {};
|
|
3617
|
+
for (const assetPath of assetPaths) {
|
|
3618
|
+
const assetFilePath = join24(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
|
|
3619
|
+
if (existsSync24(assetFilePath)) {
|
|
3620
|
+
assets[assetPath] = readFileSync16(assetFilePath, "utf-8");
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
return {
|
|
3624
|
+
indexHtml,
|
|
3625
|
+
assets
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
function isHostedSourceSnapshotFile(path) {
|
|
3629
|
+
if (/\.d\.ts$/i.test(path)) return false;
|
|
3630
|
+
return /\.(?:[cm]?[jt]sx?)$/i.test(path);
|
|
3631
|
+
}
|
|
3632
|
+
function readHostedSourceSnapshot(sourcePath) {
|
|
3633
|
+
if (!sourcePath) return void 0;
|
|
3634
|
+
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
3635
|
+
if (!existsSync24(resolvedSourcePath)) {
|
|
3636
|
+
return void 0;
|
|
3637
|
+
}
|
|
3638
|
+
const files = {};
|
|
3639
|
+
const ignoredDirNames = /* @__PURE__ */ new Set(["node_modules", ".git", ".decantr", "dist", "build", "coverage"]);
|
|
3640
|
+
const rootPrefix = basename(resolvedSourcePath);
|
|
3641
|
+
const walk = (absoluteDir, relativeDir) => {
|
|
3642
|
+
for (const entry of readdirSync6(absoluteDir, { withFileTypes: true })) {
|
|
3643
|
+
if (ignoredDirNames.has(entry.name)) continue;
|
|
3644
|
+
const absolutePath = join24(absoluteDir, entry.name);
|
|
3645
|
+
const relativePath = join24(relativeDir, entry.name).replace(/\\/g, "/");
|
|
3646
|
+
if (entry.isDirectory()) {
|
|
3647
|
+
walk(absolutePath, relativePath);
|
|
3648
|
+
continue;
|
|
3649
|
+
}
|
|
3650
|
+
if (!entry.isFile()) continue;
|
|
3651
|
+
if (!isHostedSourceSnapshotFile(relativePath)) continue;
|
|
3652
|
+
files[relativePath] = readFileSync16(absolutePath, "utf-8");
|
|
3653
|
+
}
|
|
3654
|
+
};
|
|
3655
|
+
walk(resolvedSourcePath, rootPrefix);
|
|
3656
|
+
return Object.keys(files).length > 0 ? { files } : void 0;
|
|
3657
|
+
}
|
|
3658
|
+
async function getShowcaseBenchmarkView(view = "shortlist") {
|
|
3659
|
+
const client = getPublicAPIClient();
|
|
3660
|
+
if (view === "manifest") {
|
|
3661
|
+
return client.getShowcaseManifest();
|
|
3662
|
+
}
|
|
3663
|
+
if (view === "verification") {
|
|
3664
|
+
return client.getShowcaseShortlistVerification();
|
|
3665
|
+
}
|
|
3666
|
+
return client.getShowcaseShortlist();
|
|
3667
|
+
}
|
|
3668
|
+
async function printShowcaseBenchmarks(view, jsonOutput) {
|
|
3669
|
+
const fmtBytes = (bytes) => bytes >= 1e6 ? `${(bytes / 1e6).toFixed(2)} MB` : `${Math.round(bytes / 1e3)} KB`;
|
|
3670
|
+
const data = await getShowcaseBenchmarkView(view);
|
|
3671
|
+
if (jsonOutput) {
|
|
3672
|
+
console.log(JSON.stringify(data, null, 2));
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
if (view === "manifest") {
|
|
3676
|
+
const manifest = data;
|
|
3677
|
+
console.log(heading2("Showcase Corpus"));
|
|
3678
|
+
console.log(` Active apps: ${manifest.total}`);
|
|
3679
|
+
console.log(` Shortlisted apps: ${manifest.shortlisted}`);
|
|
3680
|
+
console.log("");
|
|
3681
|
+
for (const entry of manifest.apps) {
|
|
3682
|
+
const verification = entry.verification;
|
|
3683
|
+
const verificationSummary = verification ? ` | ${verification.verificationStatus} | drift ${verification.drift.signal}` : "";
|
|
3684
|
+
console.log(` ${cyan3(entry.slug)} class ${entry.classification}${verificationSummary}`);
|
|
3685
|
+
}
|
|
3686
|
+
return;
|
|
3687
|
+
}
|
|
3688
|
+
if (view === "verification") {
|
|
3689
|
+
const report = data;
|
|
3690
|
+
console.log(heading2("Showcase Verification"));
|
|
3691
|
+
if (report.generatedAt) {
|
|
3692
|
+
console.log(` Generated: ${report.generatedAt}`);
|
|
3693
|
+
}
|
|
3694
|
+
if (report.summary) {
|
|
3695
|
+
console.log(` Passed builds: ${report.summary.passedBuilds}/${report.summary.appCount}`);
|
|
3696
|
+
console.log(` Avg build: ${report.summary.averageDurationMs} ms`);
|
|
3697
|
+
console.log(` Passed smokes: ${report.summary.passedSmokes}/${report.summary.appCount}`);
|
|
3698
|
+
console.log(` Avg smoke: ${report.summary.averageSmokeDurationMs} ms`);
|
|
3699
|
+
console.log(` Title checks: ${report.summary.appsWithTitleOkCount}/${report.summary.appCount}`);
|
|
3700
|
+
console.log(` Lang checks: ${report.summary.appsWithLangOkCount}/${report.summary.appCount}`);
|
|
3701
|
+
console.log(` Viewport checks: ${report.summary.appsWithViewportOkCount}/${report.summary.appCount}`);
|
|
3702
|
+
console.log(` Charset checks: ${report.summary.appsWithCharsetOkCount}/${report.summary.appCount}`);
|
|
3703
|
+
console.log(` No inline scripts: ${report.summary.appsWithoutInlineScriptsCount}/${report.summary.appCount}`);
|
|
3704
|
+
console.log(` CSP signals: ${report.summary.appsWithCspSignalCount}/${report.summary.appCount}`);
|
|
3705
|
+
console.log(` External script integrity ok: ${report.summary.appsWithExternalScriptIntegrityCount}/${report.summary.appCount}`);
|
|
3706
|
+
console.log(` External stylesheet integrity ok: ${report.summary.appsWithExternalStylesheetIntegrityCount}/${report.summary.appCount}`);
|
|
3707
|
+
console.log(` Route coverage: ${report.summary.appsWithRouteCoverageCount}/${report.summary.appCount}`);
|
|
3708
|
+
console.log(` Full route coverage: ${report.summary.appsWithFullRouteCoverageCount}/${report.summary.appCount}`);
|
|
3709
|
+
console.log(` Avg assets: total ${fmtBytes(report.summary.averageTotalAssetBytes)} | js ${fmtBytes(report.summary.averageJsAssetBytes)} | css ${fmtBytes(report.summary.averageCssAssetBytes)}`);
|
|
3710
|
+
console.log(` Drift: lower ${report.summary.lowerDriftCount}, moderate ${report.summary.moderateDriftCount}, elevated ${report.summary.elevatedDriftCount}`);
|
|
3711
|
+
console.log(` Pack manifests: ${report.summary.withPackManifestCount}/${report.summary.appCount}`);
|
|
3712
|
+
console.log("");
|
|
3713
|
+
}
|
|
3714
|
+
for (const entry of report.results) {
|
|
3715
|
+
console.log(` ${cyan3(entry.slug)} ${entry.verificationStatus} | smoke ${entry.smoke.passed ? "green" : entry.build.passed ? "red" : "pending"} | routes ${entry.smoke.routeDocumentsPassed}/${entry.smoke.routeDocumentsChecked}${entry.smoke.fullRouteCoverageOk ? " full" : " partial"} | js ${fmtBytes(entry.smoke.jsAssetBytes)} | drift ${entry.drift.signal} | build ${entry.build.durationMs} ms | smoke ${entry.smoke.durationMs} ms`);
|
|
3716
|
+
}
|
|
3717
|
+
return;
|
|
3718
|
+
}
|
|
3719
|
+
const shortlist = data;
|
|
3720
|
+
console.log(heading2("Showcase Shortlist"));
|
|
3721
|
+
if (shortlist.generatedAt) {
|
|
3722
|
+
console.log(` Generated: ${shortlist.generatedAt}`);
|
|
3723
|
+
}
|
|
3724
|
+
if (shortlist.summary) {
|
|
3725
|
+
console.log(` Passed builds: ${shortlist.summary.passedBuilds}/${shortlist.summary.appCount}`);
|
|
3726
|
+
console.log(` Passed smokes: ${shortlist.summary.passedSmokes}/${shortlist.summary.appCount}`);
|
|
3727
|
+
console.log(` Route coverage: ${shortlist.summary.appsWithRouteCoverageCount}/${shortlist.summary.appCount}`);
|
|
3728
|
+
console.log(` Full route coverage: ${shortlist.summary.appsWithFullRouteCoverageCount}/${shortlist.summary.appCount}`);
|
|
3729
|
+
console.log(` Drift mix: lower ${shortlist.summary.lowerDriftCount}, moderate ${shortlist.summary.moderateDriftCount}, elevated ${shortlist.summary.elevatedDriftCount}`);
|
|
3730
|
+
console.log("");
|
|
3731
|
+
}
|
|
3732
|
+
for (const entry of shortlist.apps) {
|
|
3733
|
+
const verification = entry.verification;
|
|
3734
|
+
const verificationSummary = verification ? `${verification.verificationStatus} | smoke ${verification.smoke.passed ? "green" : verification.build.passed ? "red" : "pending"} | drift ${verification.drift.signal}` : "verification pending";
|
|
3735
|
+
console.log(` ${cyan3(entry.slug)} class ${entry.classification} | ${verificationSummary}`);
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
async function printRegistryIntelligenceSummary(namespace, jsonOutput = false) {
|
|
3739
|
+
const client = getPublicAPIClient();
|
|
3740
|
+
const summary = await client.getRegistryIntelligenceSummary(
|
|
3741
|
+
namespace ? { namespace } : void 0
|
|
3742
|
+
);
|
|
3743
|
+
if (jsonOutput) {
|
|
3744
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
3745
|
+
return;
|
|
3746
|
+
}
|
|
3747
|
+
const typedSummary = summary;
|
|
3748
|
+
console.log(heading2("Registry Intelligence Summary"));
|
|
3749
|
+
console.log(` Namespace: ${typedSummary.namespace ?? "all public content"}`);
|
|
3750
|
+
console.log(` Generated: ${typedSummary.generated_at}`);
|
|
3751
|
+
console.log(` Public items: ${typedSummary.totals.total_public_items}`);
|
|
3752
|
+
console.log(` With intelligence: ${typedSummary.totals.with_intelligence}`);
|
|
3753
|
+
console.log(` Recommended: ${typedSummary.totals.recommended}`);
|
|
3754
|
+
console.log(
|
|
3755
|
+
` Sources: authored ${typedSummary.totals.authored}, benchmark ${typedSummary.totals.benchmark}, hybrid ${typedSummary.totals.hybrid}, missing ${typedSummary.totals.missing_source}`
|
|
3756
|
+
);
|
|
3757
|
+
console.log(
|
|
3758
|
+
` Verification: smoke green ${typedSummary.totals.smoke_green}, build green ${typedSummary.totals.build_green}, high confidence ${typedSummary.totals.high_confidence}, verified ${typedSummary.totals.verified_confidence}`
|
|
3759
|
+
);
|
|
3760
|
+
console.log("");
|
|
3761
|
+
for (const [type, bucket] of Object.entries(typedSummary.by_type)) {
|
|
3762
|
+
console.log(
|
|
3763
|
+
` ${cyan3(type.padEnd(10))} total ${bucket.total_public_items} | intelligence ${bucket.with_intelligence} | recommended ${bucket.recommended} | authored ${bucket.authored} | benchmark ${bucket.benchmark} | hybrid ${bucket.hybrid}`
|
|
3764
|
+
);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3768
|
+
const client = getPublicAPIClient();
|
|
3769
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join24(process.cwd(), "decantr.essence.json");
|
|
3770
|
+
if (!existsSync24(resolvedPath)) {
|
|
3771
|
+
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3772
|
+
}
|
|
3773
|
+
const essence = JSON.parse(readFileSync16(resolvedPath, "utf-8"));
|
|
3774
|
+
const bundle = await client.compileExecutionPacks(
|
|
3775
|
+
essence,
|
|
3776
|
+
namespace ? { namespace } : void 0
|
|
3777
|
+
);
|
|
3778
|
+
let writtenContextPaths = [];
|
|
3779
|
+
if (writeContext) {
|
|
3780
|
+
const contextDir = join24(process.cwd(), ".decantr", "context");
|
|
3781
|
+
mkdirSync9(contextDir, { recursive: true });
|
|
3782
|
+
const written = writeExecutionPackBundleArtifacts(
|
|
3783
|
+
contextDir,
|
|
3784
|
+
bundle
|
|
3785
|
+
);
|
|
3786
|
+
writtenContextPaths = written.paths;
|
|
3787
|
+
}
|
|
3788
|
+
if (jsonOutput) {
|
|
3789
|
+
console.log(JSON.stringify(bundle, null, 2));
|
|
3790
|
+
return;
|
|
3791
|
+
}
|
|
3792
|
+
const typedBundle = bundle;
|
|
3793
|
+
console.log(heading2("Hosted Execution Packs"));
|
|
3794
|
+
console.log(` Source essence: ${resolvedPath}`);
|
|
3795
|
+
console.log(` Essence version: ${typedBundle.sourceEssenceVersion}`);
|
|
3796
|
+
console.log(` Generated: ${typedBundle.generatedAt}`);
|
|
3797
|
+
console.log(` Adapter: ${typedBundle.scaffold.target.adapter}`);
|
|
3798
|
+
console.log(` Shell: ${typedBundle.scaffold.data.shell}`);
|
|
3799
|
+
console.log(` Theme: ${typedBundle.scaffold.data.theme.id} (${typedBundle.scaffold.data.theme.mode})`);
|
|
3800
|
+
console.log(` Pages: ${typedBundle.pages.length}`);
|
|
3801
|
+
console.log(` Sections: ${typedBundle.sections.length}`);
|
|
3802
|
+
console.log(` Mutations: ${typedBundle.mutations.length}`);
|
|
3803
|
+
if (writeContext) {
|
|
3804
|
+
console.log(` Context bundle: ${join24(process.cwd(), ".decantr", "context")}`);
|
|
3805
|
+
console.log(` Files written: ${writtenContextPaths.length}`);
|
|
3806
|
+
}
|
|
3807
|
+
console.log("");
|
|
3808
|
+
console.log(`${BOLD6}Route Plan:${RESET13}`);
|
|
3809
|
+
for (const route of typedBundle.scaffold.data.routes) {
|
|
3810
|
+
const patterns = route.patternIds.length > 0 ? route.patternIds.join(", ") : "none";
|
|
3811
|
+
console.log(` ${cyan3(route.path)} -> ${route.pageId} [${patterns}]`);
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
async function printHostedSelectedExecutionPack(packType, id, essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3815
|
+
const client = getPublicAPIClient();
|
|
3816
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join24(process.cwd(), "decantr.essence.json");
|
|
3817
|
+
if (!existsSync24(resolvedPath)) {
|
|
3818
|
+
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3819
|
+
}
|
|
3820
|
+
if ((packType === "section" || packType === "page" || packType === "mutation") && !id) {
|
|
3821
|
+
throw new Error(`Pack type "${packType}" requires an id.`);
|
|
3822
|
+
}
|
|
3823
|
+
const essence = JSON.parse(readFileSync16(resolvedPath, "utf-8"));
|
|
3824
|
+
const selected = await client.selectExecutionPack(
|
|
3825
|
+
{
|
|
3826
|
+
essence,
|
|
3827
|
+
pack_type: packType,
|
|
3828
|
+
...id ? { id } : {}
|
|
3829
|
+
},
|
|
3830
|
+
namespace ? { namespace } : void 0
|
|
3831
|
+
);
|
|
3832
|
+
let writtenContextDir = null;
|
|
3833
|
+
if (writeContext) {
|
|
3834
|
+
const contextDir = join24(process.cwd(), ".decantr", "context");
|
|
3835
|
+
mkdirSync9(contextDir, { recursive: true });
|
|
3836
|
+
writeFileSync13(join24(contextDir, "pack-manifest.json"), JSON.stringify(selected.manifest, null, 2) + "\n");
|
|
3837
|
+
const manifestEntry = selected.selector.packType === "scaffold" ? selected.manifest.scaffold : selected.selector.packType === "review" ? selected.manifest.review : selected.selector.packType === "section" ? selected.manifest.sections.find((entry) => entry.id === selected.selector.id) : selected.selector.packType === "page" ? selected.manifest.pages.find((entry) => entry.id === selected.selector.id) : selected.manifest.mutations.find((entry) => entry.id === selected.selector.id);
|
|
3838
|
+
const markdownFile = manifestEntry?.markdown ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.md`;
|
|
3839
|
+
const jsonFile = manifestEntry?.json ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.json`;
|
|
3840
|
+
writeFileSync13(join24(contextDir, markdownFile), selected.pack.renderedMarkdown);
|
|
3841
|
+
writeFileSync13(join24(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
|
|
3842
|
+
writtenContextDir = contextDir;
|
|
3843
|
+
}
|
|
3844
|
+
if (jsonOutput) {
|
|
3845
|
+
console.log(JSON.stringify(selected, null, 2));
|
|
3846
|
+
return;
|
|
3847
|
+
}
|
|
3848
|
+
const typedSelected = selected;
|
|
3849
|
+
console.log(heading2("Hosted Execution Pack"));
|
|
3850
|
+
console.log(` Source essence: ${resolvedPath}`);
|
|
3851
|
+
console.log(` Generated: ${typedSelected.generatedAt}`);
|
|
3852
|
+
console.log(` Pack type: ${typedSelected.selector.packType}`);
|
|
3853
|
+
if (typedSelected.selector.id) {
|
|
3854
|
+
console.log(` Pack id: ${typedSelected.selector.id}`);
|
|
3855
|
+
}
|
|
3856
|
+
console.log(` Adapter: ${typedSelected.pack.target.adapter}`);
|
|
3857
|
+
console.log(` Objective: ${typedSelected.pack.objective}`);
|
|
3858
|
+
if (writtenContextDir) {
|
|
3859
|
+
console.log(` Context artifact: ${writtenContextDir}`);
|
|
3860
|
+
}
|
|
3861
|
+
console.log("");
|
|
3862
|
+
process.stdout.write(typedSelected.pack.renderedMarkdown);
|
|
3863
|
+
}
|
|
3864
|
+
async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3865
|
+
const client = getPublicAPIClient();
|
|
3866
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join24(process.cwd(), "decantr.essence.json");
|
|
3867
|
+
if (!existsSync24(resolvedPath)) {
|
|
3868
|
+
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3869
|
+
}
|
|
3870
|
+
const essence = JSON.parse(readFileSync16(resolvedPath, "utf-8"));
|
|
3871
|
+
const manifest = await client.getExecutionPackManifest(
|
|
3872
|
+
essence,
|
|
3873
|
+
namespace ? { namespace } : void 0
|
|
3874
|
+
);
|
|
3875
|
+
let writtenContextDir = null;
|
|
3876
|
+
if (writeContext) {
|
|
3877
|
+
const contextDir = join24(process.cwd(), ".decantr", "context");
|
|
3878
|
+
mkdirSync9(contextDir, { recursive: true });
|
|
3879
|
+
writeFileSync13(join24(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
3880
|
+
writtenContextDir = contextDir;
|
|
3881
|
+
}
|
|
3882
|
+
if (jsonOutput) {
|
|
3883
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3886
|
+
console.log(heading2("Hosted Pack Manifest"));
|
|
3887
|
+
console.log(` Source essence: ${resolvedPath}`);
|
|
3888
|
+
console.log(` Generated: ${manifest.generatedAt}`);
|
|
3889
|
+
console.log(` Version: ${manifest.version}`);
|
|
3890
|
+
console.log(` Scaffold: ${manifest.scaffold ? "present" : "missing"}`);
|
|
3891
|
+
console.log(` Review: ${manifest.review ? "present" : "missing"}`);
|
|
3892
|
+
console.log(` Sections: ${manifest.sections.length}`);
|
|
3893
|
+
console.log(` Pages: ${manifest.pages.length}`);
|
|
3894
|
+
console.log(` Mutations: ${manifest.mutations.length}`);
|
|
3895
|
+
if (writtenContextDir) {
|
|
3896
|
+
console.log(` Context artifact: ${writtenContextDir}`);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@official") {
|
|
3900
|
+
const contextDir = join24(projectRoot, ".decantr", "context");
|
|
3901
|
+
const reviewPackPath = join24(contextDir, "review-pack.json");
|
|
3902
|
+
const manifestPath = join24(contextDir, "pack-manifest.json");
|
|
3903
|
+
if (existsSync24(reviewPackPath) && existsSync24(manifestPath)) {
|
|
3904
|
+
return { attempted: false, hydrated: false };
|
|
3905
|
+
}
|
|
3906
|
+
const essencePath = join24(projectRoot, "decantr.essence.json");
|
|
3907
|
+
if (!existsSync24(essencePath)) {
|
|
3908
|
+
return { attempted: false, hydrated: false };
|
|
3909
|
+
}
|
|
3910
|
+
const reviewHydration = await hydrateHostedReviewPackIfMissing(projectRoot, namespace);
|
|
3911
|
+
if (reviewHydration.hydrated || !reviewHydration.attempted) {
|
|
3912
|
+
return reviewHydration;
|
|
3913
|
+
}
|
|
3914
|
+
try {
|
|
3915
|
+
const client = getPublicAPIClient();
|
|
3916
|
+
const essence = JSON.parse(readFileSync16(essencePath, "utf-8"));
|
|
3917
|
+
const bundle = await client.compileExecutionPacks(essence, { namespace });
|
|
3918
|
+
mkdirSync9(contextDir, { recursive: true });
|
|
3919
|
+
writeExecutionPackBundleArtifacts(
|
|
3920
|
+
contextDir,
|
|
3921
|
+
bundle
|
|
3922
|
+
);
|
|
3923
|
+
return { attempted: true, hydrated: true, scope: "bundle" };
|
|
3924
|
+
} catch {
|
|
3925
|
+
return { attempted: true, hydrated: false };
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@official") {
|
|
3929
|
+
const contextDir = join24(projectRoot, ".decantr", "context");
|
|
3930
|
+
const reviewPackPath = join24(contextDir, "review-pack.json");
|
|
3931
|
+
const manifestPath = join24(contextDir, "pack-manifest.json");
|
|
3932
|
+
if (existsSync24(reviewPackPath) && existsSync24(manifestPath)) {
|
|
3933
|
+
return { attempted: false, hydrated: false };
|
|
3934
|
+
}
|
|
3935
|
+
const essencePath = join24(projectRoot, "decantr.essence.json");
|
|
3936
|
+
if (!existsSync24(essencePath)) {
|
|
3937
|
+
return { attempted: false, hydrated: false };
|
|
3938
|
+
}
|
|
3939
|
+
try {
|
|
3940
|
+
const client = getPublicAPIClient();
|
|
3941
|
+
const essence = JSON.parse(readFileSync16(essencePath, "utf-8"));
|
|
3942
|
+
const selected = await client.selectExecutionPack(
|
|
3943
|
+
{
|
|
3944
|
+
essence,
|
|
3945
|
+
pack_type: "review"
|
|
3946
|
+
},
|
|
3947
|
+
{ namespace }
|
|
3948
|
+
);
|
|
3949
|
+
mkdirSync9(contextDir, { recursive: true });
|
|
3950
|
+
writeFileSync13(join24(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
|
|
3951
|
+
writeFileSync13(join24(contextDir, "review-pack.json"), JSON.stringify(selected.pack, null, 2) + "\n");
|
|
3952
|
+
if (!existsSync24(manifestPath)) {
|
|
3953
|
+
writeFileSync13(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
|
|
3954
|
+
}
|
|
3955
|
+
return { attempted: true, hydrated: true, scope: "review" };
|
|
3956
|
+
} catch {
|
|
3957
|
+
return { attempted: true, hydrated: false };
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false, essencePath, treatmentsPath) {
|
|
3961
|
+
const client = getPublicAPIClient();
|
|
3962
|
+
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
3963
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join24(process.cwd(), "decantr.essence.json");
|
|
3964
|
+
const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join24(process.cwd(), "src", "styles", "treatments.css");
|
|
3965
|
+
if (!existsSync24(resolvedSourcePath)) {
|
|
3966
|
+
throw new Error(`Source file not found at ${resolvedSourcePath}`);
|
|
3967
|
+
}
|
|
3968
|
+
if (!existsSync24(resolvedEssencePath)) {
|
|
3969
|
+
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
3970
|
+
}
|
|
3971
|
+
const code = readFileSync16(resolvedSourcePath, "utf-8");
|
|
3972
|
+
const essence = JSON.parse(readFileSync16(resolvedEssencePath, "utf-8"));
|
|
3973
|
+
const treatmentsCss = existsSync24(resolvedTreatmentsPath) ? readFileSync16(resolvedTreatmentsPath, "utf-8") : void 0;
|
|
3974
|
+
const report = await client.critiqueFile(
|
|
3975
|
+
{
|
|
3976
|
+
essence,
|
|
3977
|
+
filePath: sourcePath,
|
|
3978
|
+
code,
|
|
3979
|
+
treatmentsCss
|
|
3980
|
+
},
|
|
3981
|
+
namespace ? { namespace } : void 0
|
|
3982
|
+
);
|
|
3983
|
+
if (jsonOutput) {
|
|
3984
|
+
console.log(JSON.stringify(report, null, 2));
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
console.log(heading2("Hosted File Critique"));
|
|
3988
|
+
console.log(` Source file: ${resolvedSourcePath}`);
|
|
3989
|
+
console.log(` Essence: ${resolvedEssencePath}`);
|
|
3990
|
+
if (treatmentsCss) {
|
|
3991
|
+
console.log(` Treatments: ${resolvedTreatmentsPath}`);
|
|
3992
|
+
}
|
|
3993
|
+
printFileCritiqueReport(report);
|
|
3994
|
+
}
|
|
3995
|
+
async function printHostedProjectAudit(namespace, jsonOutput = false, essencePath, distPath, sourcesPath) {
|
|
3996
|
+
const client = getPublicAPIClient();
|
|
3997
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join24(process.cwd(), "decantr.essence.json");
|
|
3998
|
+
if (!existsSync24(resolvedEssencePath)) {
|
|
3999
|
+
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
4000
|
+
}
|
|
4001
|
+
const essence = JSON.parse(readFileSync16(resolvedEssencePath, "utf-8"));
|
|
4002
|
+
const dist = readHostedDistSnapshot(distPath);
|
|
4003
|
+
const sources = readHostedSourceSnapshot(sourcesPath);
|
|
4004
|
+
const report = await client.auditProject(
|
|
4005
|
+
{
|
|
4006
|
+
essence,
|
|
4007
|
+
dist,
|
|
4008
|
+
sources
|
|
4009
|
+
},
|
|
4010
|
+
namespace ? { namespace } : void 0
|
|
4011
|
+
);
|
|
4012
|
+
if (jsonOutput) {
|
|
4013
|
+
console.log(JSON.stringify(report, null, 2));
|
|
4014
|
+
return;
|
|
4015
|
+
}
|
|
4016
|
+
console.log(heading2("Hosted Project Audit"));
|
|
4017
|
+
console.log(` Essence: ${resolvedEssencePath}`);
|
|
4018
|
+
console.log(` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join24(process.cwd(), "dist") : "none"}`);
|
|
4019
|
+
console.log(` Source snapshot: ${sources && sourcesPath ? resolveUserPath(sourcesPath) : "none"}`);
|
|
4020
|
+
printProjectAuditReport(report);
|
|
4021
|
+
}
|
|
4022
|
+
async function cmdSearch(query, type, sort, recommended, intelligenceSource) {
|
|
3319
4023
|
const apiClient = getAPIClient();
|
|
3320
4024
|
try {
|
|
3321
|
-
const response = await apiClient.search({
|
|
4025
|
+
const response = await apiClient.search({
|
|
4026
|
+
q: query,
|
|
4027
|
+
type,
|
|
4028
|
+
sort,
|
|
4029
|
+
recommended,
|
|
4030
|
+
intelligenceSource
|
|
4031
|
+
});
|
|
3322
4032
|
const results = response.results;
|
|
3323
4033
|
if (results.length === 0) {
|
|
3324
4034
|
console.log(dim3(`No results for "${query}"`));
|
|
@@ -3328,6 +4038,10 @@ async function cmdSearch(query, type) {
|
|
|
3328
4038
|
for (const r of results) {
|
|
3329
4039
|
console.log(` ${cyan3(r.type.padEnd(12))} ${BOLD6}${r.slug}${RESET13}`);
|
|
3330
4040
|
console.log(` ${dim3(r.description || "")}`);
|
|
4041
|
+
const intelligenceSummary = formatIntelligenceSummary(r.intelligence);
|
|
4042
|
+
if (intelligenceSummary) {
|
|
4043
|
+
console.log(` ${dim3(intelligenceSummary)}`);
|
|
4044
|
+
}
|
|
3331
4045
|
console.log("");
|
|
3332
4046
|
}
|
|
3333
4047
|
} catch {
|
|
@@ -3372,40 +4086,32 @@ async function cmdSuggest(query, type) {
|
|
|
3372
4086
|
}
|
|
3373
4087
|
}
|
|
3374
4088
|
async function cmdGet(type, id) {
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
|
|
4089
|
+
if (!isGetContentType(type)) {
|
|
4090
|
+
console.error(error3(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
|
|
3378
4091
|
process.exitCode = 1;
|
|
3379
4092
|
return;
|
|
3380
4093
|
}
|
|
3381
|
-
const
|
|
3382
|
-
pattern: "patterns",
|
|
3383
|
-
archetype: "archetypes",
|
|
3384
|
-
theme: "themes",
|
|
3385
|
-
blueprint: "blueprints",
|
|
3386
|
-
shell: "shells"
|
|
3387
|
-
};
|
|
3388
|
-
const apiType = typeMap[type];
|
|
4094
|
+
const apiType = CONTENT_TYPE_TO_API_CONTENT_TYPE3[type];
|
|
3389
4095
|
const registryClient = new RegistryClient({
|
|
3390
|
-
cacheDir:
|
|
4096
|
+
cacheDir: join24(process.cwd(), ".decantr", "cache")
|
|
3391
4097
|
});
|
|
3392
4098
|
const result = await registryClient.fetchContentItem(apiType, id);
|
|
3393
4099
|
if (result) {
|
|
3394
4100
|
console.log(JSON.stringify(result.data, null, 2));
|
|
3395
4101
|
return;
|
|
3396
4102
|
}
|
|
3397
|
-
const currentDir = dirname2(
|
|
4103
|
+
const currentDir = dirname2(fileURLToPath2(import.meta.url));
|
|
3398
4104
|
const bundledCandidates = [
|
|
3399
|
-
|
|
4105
|
+
join24(currentDir, "bundled", apiType, `${id}.json`),
|
|
3400
4106
|
// Running from src/
|
|
3401
|
-
|
|
4107
|
+
join24(currentDir, "..", "src", "bundled", apiType, `${id}.json`),
|
|
3402
4108
|
// Running from dist/
|
|
3403
|
-
|
|
4109
|
+
join24(currentDir, "..", "bundled", apiType, `${id}.json`)
|
|
3404
4110
|
// Alternative dist layout
|
|
3405
4111
|
];
|
|
3406
|
-
const bundledPath = bundledCandidates.find((p) =>
|
|
4112
|
+
const bundledPath = bundledCandidates.find((p) => existsSync24(p)) || null;
|
|
3407
4113
|
if (bundledPath) {
|
|
3408
|
-
const data = JSON.parse(
|
|
4114
|
+
const data = JSON.parse(readFileSync16(bundledPath, "utf-8"));
|
|
3409
4115
|
console.log(JSON.stringify(data, null, 2));
|
|
3410
4116
|
return;
|
|
3411
4117
|
}
|
|
@@ -3413,55 +4119,11 @@ async function cmdGet(type, id) {
|
|
|
3413
4119
|
process.exitCode = 1;
|
|
3414
4120
|
return;
|
|
3415
4121
|
}
|
|
3416
|
-
function buildRegistryContext() {
|
|
3417
|
-
const themeRegistry = /* @__PURE__ */ new Map();
|
|
3418
|
-
const patternRegistry = /* @__PURE__ */ new Map();
|
|
3419
|
-
const projectRoot = process.cwd();
|
|
3420
|
-
const cacheDir = join23(projectRoot, ".decantr", "cache");
|
|
3421
|
-
const customDir = join23(projectRoot, ".decantr", "custom");
|
|
3422
|
-
const cachedThemesDir = join23(cacheDir, "@official", "themes");
|
|
3423
|
-
try {
|
|
3424
|
-
if (existsSync23(cachedThemesDir)) {
|
|
3425
|
-
for (const f of readdirSync6(cachedThemesDir).filter((f2) => f2.endsWith(".json") && f2 !== "index.json")) {
|
|
3426
|
-
const data = JSON.parse(readFileSync15(join23(cachedThemesDir, f), "utf-8"));
|
|
3427
|
-
if (data.id && !themeRegistry.has(data.id)) {
|
|
3428
|
-
themeRegistry.set(data.id, { modes: data.modes || ["light", "dark"] });
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3432
|
-
} catch {
|
|
3433
|
-
}
|
|
3434
|
-
const customThemesDir = join23(customDir, "themes");
|
|
3435
|
-
try {
|
|
3436
|
-
if (existsSync23(customThemesDir)) {
|
|
3437
|
-
for (const f of readdirSync6(customThemesDir).filter((f2) => f2.endsWith(".json"))) {
|
|
3438
|
-
const data = JSON.parse(readFileSync15(join23(customThemesDir, f), "utf-8"));
|
|
3439
|
-
if (data.id) {
|
|
3440
|
-
themeRegistry.set(`custom:${data.id}`, { modes: data.modes || ["light", "dark"] });
|
|
3441
|
-
}
|
|
3442
|
-
}
|
|
3443
|
-
}
|
|
3444
|
-
} catch {
|
|
3445
|
-
}
|
|
3446
|
-
const cachedPatternsDir = join23(cacheDir, "@official", "patterns");
|
|
3447
|
-
try {
|
|
3448
|
-
if (existsSync23(cachedPatternsDir)) {
|
|
3449
|
-
for (const f of readdirSync6(cachedPatternsDir).filter((f2) => f2.endsWith(".json") && f2 !== "index.json")) {
|
|
3450
|
-
const data = JSON.parse(readFileSync15(join23(cachedPatternsDir, f), "utf-8"));
|
|
3451
|
-
if (data.id && !patternRegistry.has(data.id)) {
|
|
3452
|
-
patternRegistry.set(data.id, data);
|
|
3453
|
-
}
|
|
3454
|
-
}
|
|
3455
|
-
}
|
|
3456
|
-
} catch {
|
|
3457
|
-
}
|
|
3458
|
-
return { themeRegistry, patternRegistry };
|
|
3459
|
-
}
|
|
3460
4122
|
async function cmdValidate(path) {
|
|
3461
|
-
const essencePath = path ||
|
|
4123
|
+
const essencePath = path || join24(process.cwd(), "decantr.essence.json");
|
|
3462
4124
|
let raw;
|
|
3463
4125
|
try {
|
|
3464
|
-
raw =
|
|
4126
|
+
raw = readFileSync16(essencePath, "utf-8");
|
|
3465
4127
|
} catch {
|
|
3466
4128
|
console.error(error3(`Could not read ${essencePath}`));
|
|
3467
4129
|
process.exitCode = 1;
|
|
@@ -3491,7 +4153,7 @@ async function cmdValidate(path) {
|
|
|
3491
4153
|
console.log(`${YELLOW9}Tip: Run \`decantr migrate\` to upgrade to v3 format.${RESET13}`);
|
|
3492
4154
|
}
|
|
3493
4155
|
try {
|
|
3494
|
-
const { themeRegistry, patternRegistry } =
|
|
4156
|
+
const { themeRegistry, patternRegistry } = buildGuardRegistryContext(process.cwd());
|
|
3495
4157
|
const violations = evaluateGuard(essence, { themeRegistry, patternRegistry });
|
|
3496
4158
|
if (violations.length > 0) {
|
|
3497
4159
|
console.log(heading2("Guard violations:"));
|
|
@@ -3508,17 +4170,22 @@ async function cmdValidate(path) {
|
|
|
3508
4170
|
} catch {
|
|
3509
4171
|
}
|
|
3510
4172
|
}
|
|
3511
|
-
async function cmdList(type) {
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
console.error(error3(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
|
|
4173
|
+
async function cmdList(type, sort, recommended, intelligenceSource) {
|
|
4174
|
+
if (!isApiContentType(type)) {
|
|
4175
|
+
console.error(error3(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`));
|
|
3515
4176
|
process.exitCode = 1;
|
|
3516
4177
|
return;
|
|
3517
4178
|
}
|
|
3518
4179
|
const registryClient = new RegistryClient({
|
|
3519
|
-
cacheDir:
|
|
4180
|
+
cacheDir: join24(process.cwd(), ".decantr", "cache")
|
|
3520
4181
|
});
|
|
3521
|
-
const result = await registryClient.fetchContentList(
|
|
4182
|
+
const result = await registryClient.fetchContentList(
|
|
4183
|
+
type,
|
|
4184
|
+
void 0,
|
|
4185
|
+
sort,
|
|
4186
|
+
recommended,
|
|
4187
|
+
intelligenceSource
|
|
4188
|
+
);
|
|
3522
4189
|
const items = result.data.items;
|
|
3523
4190
|
if (items.length === 0) {
|
|
3524
4191
|
console.log(dim3(`No ${type} found.`));
|
|
@@ -3547,6 +4214,12 @@ async function cmdList(type) {
|
|
|
3547
4214
|
console.log(heading2(`${items.length} ${type} found`));
|
|
3548
4215
|
for (const item of items) {
|
|
3549
4216
|
console.log(` ${cyan3(item.id)} ${dim3(item.description || item.name || "")}`);
|
|
4217
|
+
const intelligenceSummary = formatIntelligenceSummary(
|
|
4218
|
+
item.intelligence
|
|
4219
|
+
);
|
|
4220
|
+
if (intelligenceSummary) {
|
|
4221
|
+
console.log(` ${dim3(intelligenceSummary)}`);
|
|
4222
|
+
}
|
|
3550
4223
|
}
|
|
3551
4224
|
}
|
|
3552
4225
|
}
|
|
@@ -3562,12 +4235,34 @@ async function cmdInit(args) {
|
|
|
3562
4235
|
return;
|
|
3563
4236
|
}
|
|
3564
4237
|
}
|
|
4238
|
+
const requestedBlueprint = Boolean(args.blueprint);
|
|
4239
|
+
const requestedArchetype = Boolean(args.archetype);
|
|
4240
|
+
const requestedTheme = Boolean(args.theme);
|
|
4241
|
+
let offlineSeed = { seeded: false, strategy: null };
|
|
4242
|
+
if (args.offline) {
|
|
4243
|
+
offlineSeed = seedOfflineRegistry(projectRoot, projectRoot);
|
|
4244
|
+
if (offlineSeed.seeded) {
|
|
4245
|
+
console.log(dim3(` Seeded offline registry content from ${offlineSeed.strategy}.`));
|
|
4246
|
+
} else if (requestedBlueprint || requestedArchetype) {
|
|
4247
|
+
console.log(error3("\nOffline blueprint/archetype scaffolding requires a local Decantr content source."));
|
|
4248
|
+
console.log(dim3("Set DECANTR_CONTENT_DIR, seed .decantr/cache or .decantr/custom, or run without --offline."));
|
|
4249
|
+
process.exitCode = 1;
|
|
4250
|
+
return;
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
3565
4253
|
const registryClient = new RegistryClient({
|
|
3566
|
-
cacheDir:
|
|
4254
|
+
cacheDir: join24(projectRoot, ".decantr", "cache"),
|
|
3567
4255
|
apiUrl: args.registry,
|
|
3568
4256
|
offline: args.offline
|
|
3569
4257
|
});
|
|
3570
4258
|
const apiAvailable = await registryClient.checkApiAvailability();
|
|
4259
|
+
if (!apiAvailable && !args.offline && (requestedBlueprint || requestedArchetype)) {
|
|
4260
|
+
const fallbackSeed = seedOfflineRegistry(projectRoot, projectRoot);
|
|
4261
|
+
if (fallbackSeed.seeded) {
|
|
4262
|
+
offlineSeed = fallbackSeed;
|
|
4263
|
+
console.log(dim3(` Seeded local registry fallback from ${fallbackSeed.strategy}.`));
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
3571
4266
|
let selectedBlueprint = "default";
|
|
3572
4267
|
let registrySource = "cache";
|
|
3573
4268
|
if (args.yes) {
|
|
@@ -3589,8 +4284,15 @@ ${YELLOW9}You're offline. Scaffolding minimal Decantr project.${RESET13}`);
|
|
|
3589
4284
|
console.log("");
|
|
3590
4285
|
console.log(" Next steps:");
|
|
3591
4286
|
console.log(` 1. Run ${cyan3("decantr sync")} when online`);
|
|
3592
|
-
console.log(` 2.
|
|
3593
|
-
console.log(` 3.
|
|
4287
|
+
console.log(` 2. Run ${cyan3("decantr refresh")} after syncing to generate scaffold, section, and page packs`);
|
|
4288
|
+
console.log(` 3. Read ${cyan3("DECANTR.md")} and the generated ${cyan3(".decantr/context/*")} files before implementation`);
|
|
4289
|
+
console.log(` 4. Use ${cyan3("decantr create <type> <name>")} to create custom content if needed`);
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
if (requestedBlueprint || requestedArchetype) {
|
|
4293
|
+
console.log(error3("\nThe requested blueprint/archetype could not be resolved from the hosted registry or local cache."));
|
|
4294
|
+
console.log(dim3("Run `decantr sync`, set DECANTR_CONTENT_DIR, or retry when the registry is reachable."));
|
|
4295
|
+
process.exitCode = 1;
|
|
3594
4296
|
return;
|
|
3595
4297
|
}
|
|
3596
4298
|
console.log(`
|
|
@@ -3644,8 +4346,8 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3644
4346
|
if (blueprintResult) {
|
|
3645
4347
|
const blueprint = blueprintResult.data;
|
|
3646
4348
|
if (blueprint.theme) {
|
|
3647
|
-
if (!userExplicit.theme &&
|
|
3648
|
-
options.theme = blueprint.theme.id
|
|
4349
|
+
if (!userExplicit.theme && blueprint.theme.id) {
|
|
4350
|
+
options.theme = blueprint.theme.id;
|
|
3649
4351
|
}
|
|
3650
4352
|
if (!userExplicit.mode && blueprint.theme.mode) {
|
|
3651
4353
|
options.mode = blueprint.theme.mode;
|
|
@@ -3663,9 +4365,9 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3663
4365
|
for (const entry of entries) {
|
|
3664
4366
|
const id = typeof entry === "string" ? entry : entry.archetype;
|
|
3665
4367
|
const r = await registryClient.fetchArchetype(id);
|
|
3666
|
-
results.push([id, r?.data
|
|
4368
|
+
results.push([id, r?.data ? mapRegistryArchetypeToArchetypeData(r.data) : null]);
|
|
3667
4369
|
}
|
|
3668
|
-
const archetypeMap = new Map(results
|
|
4370
|
+
const archetypeMap = new Map(results);
|
|
3669
4371
|
const composed = composeArchetypes(entries, archetypeMap);
|
|
3670
4372
|
const primaryId = typeof entries[0] === "string" ? entries[0] : entries[0].archetype;
|
|
3671
4373
|
archetypeData = {
|
|
@@ -3700,9 +4402,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3700
4402
|
if (page.patterns) {
|
|
3701
4403
|
for (const ref of page.patterns) allPatternIds.add(ref.pattern);
|
|
3702
4404
|
}
|
|
3703
|
-
for (const
|
|
3704
|
-
if (typeof item === "string") allPatternIds.add(item);
|
|
3705
|
-
}
|
|
4405
|
+
for (const patternId of collectPatternIdsFromItems(page.layout)) allPatternIds.add(patternId);
|
|
3706
4406
|
}
|
|
3707
4407
|
}
|
|
3708
4408
|
patternSpecs = {};
|
|
@@ -3711,14 +4411,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3711
4411
|
try {
|
|
3712
4412
|
const result2 = await registryClient.fetchPattern(pid);
|
|
3713
4413
|
if (result2) {
|
|
3714
|
-
|
|
3715
|
-
const defaultPreset = inner.default_preset || "standard";
|
|
3716
|
-
const preset = inner.presets?.[defaultPreset];
|
|
3717
|
-
patternSpecs[pid] = {
|
|
3718
|
-
description: inner.description || "",
|
|
3719
|
-
components: inner.components || [],
|
|
3720
|
-
slots: preset?.layout?.slots || {}
|
|
3721
|
-
};
|
|
4414
|
+
patternSpecs[pid] = mapRegistryPatternToPatternSpecSummary(result2.data, void 0, false);
|
|
3722
4415
|
}
|
|
3723
4416
|
} catch {
|
|
3724
4417
|
}
|
|
@@ -3727,7 +4420,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3727
4420
|
const zoneInputs = [];
|
|
3728
4421
|
for (const entry of entries) {
|
|
3729
4422
|
const arcId = typeof entry === "string" ? entry : entry.archetype;
|
|
3730
|
-
const explicitRole = typeof entry === "
|
|
4423
|
+
const explicitRole = typeof entry === "string" ? void 0 : entry.role;
|
|
3731
4424
|
const archData = archetypeMap.get(arcId);
|
|
3732
4425
|
if (archData) {
|
|
3733
4426
|
zoneInputs.push({
|
|
@@ -3758,13 +4451,25 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3758
4451
|
) : "";
|
|
3759
4452
|
}
|
|
3760
4453
|
} else {
|
|
4454
|
+
if (requestedBlueprint) {
|
|
4455
|
+
console.log(error3(` Error: Could not fetch blueprint "${options.blueprint}".`));
|
|
4456
|
+
console.log(dim3("Resolve local registry content or retry against the hosted registry."));
|
|
4457
|
+
process.exitCode = 1;
|
|
4458
|
+
return;
|
|
4459
|
+
}
|
|
3761
4460
|
console.log(`${YELLOW9} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET13}`);
|
|
3762
4461
|
}
|
|
3763
4462
|
} else if (options.archetype) {
|
|
3764
4463
|
const archetypeResult = await registryClient.fetchArchetype(options.archetype);
|
|
3765
4464
|
if (archetypeResult) {
|
|
3766
|
-
archetypeData = archetypeResult.data;
|
|
4465
|
+
archetypeData = mapRegistryArchetypeToArchetypeData(archetypeResult.data);
|
|
3767
4466
|
} else {
|
|
4467
|
+
if (requestedArchetype) {
|
|
4468
|
+
console.log(error3(` Error: Could not fetch archetype "${options.archetype}".`));
|
|
4469
|
+
console.log(dim3("Resolve local registry content or retry against the hosted registry."));
|
|
4470
|
+
process.exitCode = 1;
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
3768
4473
|
console.log(`${YELLOW9} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET13}`);
|
|
3769
4474
|
}
|
|
3770
4475
|
}
|
|
@@ -3772,24 +4477,14 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3772
4477
|
if (options.theme) {
|
|
3773
4478
|
const themeResult = await registryClient.fetchTheme(options.theme);
|
|
3774
4479
|
if (themeResult) {
|
|
3775
|
-
|
|
3776
|
-
themeData = {
|
|
3777
|
-
seed: theme.seed,
|
|
3778
|
-
palette: theme.palette,
|
|
3779
|
-
tokens: theme.tokens,
|
|
3780
|
-
cvd_support: theme.cvd_support,
|
|
3781
|
-
typography: theme.typography,
|
|
3782
|
-
motion: theme.motion,
|
|
3783
|
-
decorators: theme.decorators,
|
|
3784
|
-
treatments: theme.treatments,
|
|
3785
|
-
spatial: theme.spatial,
|
|
3786
|
-
radius: theme.radius,
|
|
3787
|
-
shell: theme.shell,
|
|
3788
|
-
effects: theme.effects,
|
|
3789
|
-
compositions: theme.compositions,
|
|
3790
|
-
pattern_preferences: theme.pattern_preferences
|
|
3791
|
-
};
|
|
4480
|
+
themeData = mapRegistryThemeToThemeData(themeResult.data);
|
|
3792
4481
|
} else {
|
|
4482
|
+
if (requestedTheme) {
|
|
4483
|
+
console.log(error3(` Error: Could not fetch theme "${options.theme}".`));
|
|
4484
|
+
console.log(dim3("Resolve local registry content or retry against the hosted registry."));
|
|
4485
|
+
process.exitCode = 1;
|
|
4486
|
+
return;
|
|
4487
|
+
}
|
|
3793
4488
|
console.log(`${YELLOW9} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET13}`);
|
|
3794
4489
|
}
|
|
3795
4490
|
}
|
|
@@ -3819,8 +4514,12 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3819
4514
|
}
|
|
3820
4515
|
console.log("");
|
|
3821
4516
|
console.log(" Next steps:");
|
|
3822
|
-
console.log(" 1.
|
|
3823
|
-
console.log(" 2.
|
|
4517
|
+
console.log(" 1. Read DECANTR.md for methodology, CSS approach, and guard rules");
|
|
4518
|
+
console.log(" 2. Read .decantr/context/scaffold-pack.md first, then .decantr/context/scaffold.md");
|
|
4519
|
+
console.log(" 3. Read the matching section and page packs before implementing each route");
|
|
4520
|
+
console.log(" 4. Build the shell and route structure first, then implement the pages");
|
|
4521
|
+
console.log(" 5. Run decantr check and decantr audit after implementation");
|
|
4522
|
+
console.log(" 6. Explore more at decantr.ai/registry");
|
|
3824
4523
|
console.log("");
|
|
3825
4524
|
console.log(" Commands:");
|
|
3826
4525
|
console.log(` ${cyan3("decantr status")} Project health`);
|
|
@@ -3830,7 +4529,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
3830
4529
|
console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
|
|
3831
4530
|
console.log(` ${cyan3("decantr check")} Detect drift issues`);
|
|
3832
4531
|
console.log(` ${cyan3("decantr migrate")} Migrate v2 essence to v3`);
|
|
3833
|
-
const essenceContent =
|
|
4532
|
+
const essenceContent = readFileSync16(result.essencePath, "utf-8");
|
|
3834
4533
|
const essence = JSON.parse(essenceContent);
|
|
3835
4534
|
if (essence.version !== "3.1.0") {
|
|
3836
4535
|
const validation = validateEssence2(essence);
|
|
@@ -3877,16 +4576,16 @@ Validation warnings: ${validation.errors.join(", ")}`));
|
|
|
3877
4576
|
}
|
|
3878
4577
|
async function cmdStatus() {
|
|
3879
4578
|
const projectRoot = process.cwd();
|
|
3880
|
-
const essencePath =
|
|
3881
|
-
const projectJsonPath =
|
|
4579
|
+
const essencePath = join24(projectRoot, "decantr.essence.json");
|
|
4580
|
+
const projectJsonPath = join24(projectRoot, ".decantr", "project.json");
|
|
3882
4581
|
console.log(heading2("Decantr Project Status"));
|
|
3883
|
-
if (!
|
|
4582
|
+
if (!existsSync24(essencePath)) {
|
|
3884
4583
|
console.log(`${RED11}No decantr.essence.json found.${RESET13}`);
|
|
3885
4584
|
console.log(dim3('Run "decantr init" to create one.'));
|
|
3886
4585
|
return;
|
|
3887
4586
|
}
|
|
3888
4587
|
try {
|
|
3889
|
-
const essence = JSON.parse(
|
|
4588
|
+
const essence = JSON.parse(readFileSync16(essencePath, "utf-8"));
|
|
3890
4589
|
const validation = validateEssence2(essence);
|
|
3891
4590
|
const essenceVersion = isV36(essence) ? "v3" : "v2";
|
|
3892
4591
|
console.log(`${BOLD6}Essence:${RESET13}`);
|
|
@@ -3897,8 +4596,12 @@ async function cmdStatus() {
|
|
|
3897
4596
|
}
|
|
3898
4597
|
if (isV36(essence)) {
|
|
3899
4598
|
const v3 = essence;
|
|
4599
|
+
const sections = v3.blueprint.sections ?? [];
|
|
4600
|
+
const flatPages = sections.length > 0 ? sections.flatMap((section) => section.pages ?? []) : v3.blueprint.pages ?? [];
|
|
4601
|
+
const resolvedShell = sections.find((section) => section.role === "primary")?.shell || sections[0]?.shell || v3.blueprint.shell || "unknown";
|
|
4602
|
+
const resolvedFeatures = v3.blueprint.features ?? [];
|
|
3900
4603
|
console.log(` ${BOLD6}DNA:${RESET13}`);
|
|
3901
|
-
console.log(` Theme: ${v3.dna.theme.
|
|
4604
|
+
console.log(` Theme: ${v3.dna.theme.id} (${v3.dna.theme.mode})`);
|
|
3902
4605
|
console.log(` Spacing: ${v3.dna.spacing.density} density, ${v3.dna.spacing.content_gap} gap`);
|
|
3903
4606
|
console.log(` Typography: ${v3.dna.typography.scale} scale`);
|
|
3904
4607
|
console.log(` Radius: ${v3.dna.radius.philosophy} (base ${v3.dna.radius.base}px)`);
|
|
@@ -3906,9 +4609,12 @@ async function cmdStatus() {
|
|
|
3906
4609
|
console.log(` Accessibility: WCAG ${v3.dna.accessibility.wcag_level}`);
|
|
3907
4610
|
console.log(` Personality: ${v3.dna.personality.join(", ")}`);
|
|
3908
4611
|
console.log(` ${BOLD6}Blueprint:${RESET13}`);
|
|
3909
|
-
console.log(` Shell: ${
|
|
3910
|
-
console.log(` Pages: ${
|
|
3911
|
-
|
|
4612
|
+
console.log(` Shell: ${resolvedShell}`);
|
|
4613
|
+
console.log(` Pages: ${flatPages.length}`);
|
|
4614
|
+
if (sections.length > 0) {
|
|
4615
|
+
console.log(` Sections: ${sections.length}`);
|
|
4616
|
+
}
|
|
4617
|
+
console.log(` Features: ${resolvedFeatures.length > 0 ? resolvedFeatures.join(", ") : "none"}`);
|
|
3912
4618
|
console.log(` ${BOLD6}Meta:${RESET13}`);
|
|
3913
4619
|
console.log(` Archetype: ${v3.meta.archetype}`);
|
|
3914
4620
|
console.log(` Target: ${v3.meta.target}`);
|
|
@@ -3918,7 +4624,7 @@ async function cmdStatus() {
|
|
|
3918
4624
|
const theme = e.theme;
|
|
3919
4625
|
const guard = e.guard;
|
|
3920
4626
|
const structure = e.structure;
|
|
3921
|
-
console.log(` Theme: ${theme?.
|
|
4627
|
+
console.log(` Theme: ${theme?.id || "unknown"} (${theme?.mode || "unknown"})`);
|
|
3922
4628
|
console.log(` Guard: ${guard?.mode || "unknown"}`);
|
|
3923
4629
|
console.log(` Pages: ${(structure || []).length}`);
|
|
3924
4630
|
console.log(` ${YELLOW9}Tip: Run \`decantr migrate\` to upgrade to v3.${RESET13}`);
|
|
@@ -3928,9 +4634,9 @@ async function cmdStatus() {
|
|
|
3928
4634
|
}
|
|
3929
4635
|
console.log("");
|
|
3930
4636
|
console.log(`${BOLD6}Sync Status:${RESET13}`);
|
|
3931
|
-
if (
|
|
4637
|
+
if (existsSync24(projectJsonPath)) {
|
|
3932
4638
|
try {
|
|
3933
|
-
const projectJson = JSON.parse(
|
|
4639
|
+
const projectJson = JSON.parse(readFileSync16(projectJsonPath, "utf-8"));
|
|
3934
4640
|
const syncStatus = projectJson.sync?.status || "unknown";
|
|
3935
4641
|
const lastSync = projectJson.sync?.lastSync || "never";
|
|
3936
4642
|
const source = projectJson.sync?.registrySource || "unknown";
|
|
@@ -3948,7 +4654,7 @@ async function cmdStatus() {
|
|
|
3948
4654
|
}
|
|
3949
4655
|
async function cmdSync() {
|
|
3950
4656
|
const projectRoot = process.cwd();
|
|
3951
|
-
const cacheDir =
|
|
4657
|
+
const cacheDir = join24(projectRoot, ".decantr", "cache");
|
|
3952
4658
|
console.log(heading2("Syncing registry content..."));
|
|
3953
4659
|
const result = await syncRegistry(cacheDir);
|
|
3954
4660
|
if (result.synced.length > 0) {
|
|
@@ -3964,47 +4670,110 @@ async function cmdSync() {
|
|
|
3964
4670
|
}
|
|
3965
4671
|
}
|
|
3966
4672
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
console.log(heading2("Auditing project..."));
|
|
3971
|
-
if (!existsSync23(essencePath)) {
|
|
3972
|
-
console.log(`${RED11}No decantr.essence.json found.${RESET13}`);
|
|
3973
|
-
process.exitCode = 1;
|
|
4673
|
+
function printVerificationFindings(findings) {
|
|
4674
|
+
if (findings.length === 0) {
|
|
4675
|
+
console.log(success3("No findings."));
|
|
3974
4676
|
return;
|
|
3975
4677
|
}
|
|
4678
|
+
for (const finding of findings) {
|
|
4679
|
+
const color = finding.severity === "error" ? RED11 : finding.severity === "warn" ? YELLOW9 : CYAN7;
|
|
4680
|
+
console.log(` ${color}[${finding.severity.toUpperCase()}]${RESET13} ${finding.category}: ${finding.message}`);
|
|
4681
|
+
for (const evidence of finding.evidence) {
|
|
4682
|
+
console.log(` ${DIM13}${evidence}${RESET13}`);
|
|
4683
|
+
}
|
|
4684
|
+
if (finding.suggestedFix) {
|
|
4685
|
+
console.log(` ${DIM13}Fix: ${finding.suggestedFix}${RESET13}`);
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
function printProjectAuditReport(report) {
|
|
4690
|
+
if (report.valid) {
|
|
4691
|
+
console.log(success3("Project contract is valid."));
|
|
4692
|
+
} else {
|
|
4693
|
+
console.log(`${RED11}Project audit found blocking issues.${RESET13}`);
|
|
4694
|
+
}
|
|
4695
|
+
console.log("");
|
|
4696
|
+
console.log(`${BOLD6}Summary:${RESET13}`);
|
|
4697
|
+
console.log(` Essence version: ${report.summary.essenceVersion ?? "missing"}`);
|
|
4698
|
+
console.log(` Pages defined: ${report.summary.pageCount}`);
|
|
4699
|
+
console.log(` Pack manifest: ${report.summary.packManifestPresent ? "present" : "missing"}`);
|
|
4700
|
+
console.log(` Review pack: ${report.summary.reviewPackPresent ? "present" : "missing"}`);
|
|
4701
|
+
const runtimeStatus = report.summary.runtimeAuditChecked ? report.summary.runtimePassed ? "passed" : "failed" : report.runtimeAudit.distPresent ? "incomplete" : "pending (no dist/)";
|
|
4702
|
+
console.log(` Runtime audit: ${runtimeStatus}`);
|
|
4703
|
+
if (report.summary.runtimeAuditChecked && report.runtimeAudit.assetCount > 0) {
|
|
4704
|
+
const fmt = (bytes) => bytes >= 1e6 ? `${(bytes / 1e6).toFixed(2)} MB` : `${Math.round(bytes / 1e3)} KB`;
|
|
4705
|
+
console.log(
|
|
4706
|
+
` Built assets: total ${fmt(report.runtimeAudit.totalAssetBytes)} | js ${fmt(report.runtimeAudit.jsAssetBytes)} | css ${fmt(report.runtimeAudit.cssAssetBytes)}`
|
|
4707
|
+
);
|
|
4708
|
+
console.log(
|
|
4709
|
+
` Document hardening: lang ${report.runtimeAudit.langOk ? "ok" : "missing"} | viewport ${report.runtimeAudit.viewportOk ? "ok" : "missing"} | charset ${report.runtimeAudit.charsetOk ? "ok" : "missing"} | csp ${report.runtimeAudit.cspSignalOk ? "present" : "missing"}`
|
|
4710
|
+
);
|
|
4711
|
+
console.log(
|
|
4712
|
+
` Route document shell: root docs ${report.runtimeAudit.routeDocumentsPassed}/${report.runtimeAudit.routeDocumentsChecked} | hardened docs ${report.runtimeAudit.routeDocumentsHardenedCount}/${report.runtimeAudit.routeDocumentsChecked}`
|
|
4713
|
+
);
|
|
4714
|
+
console.log(
|
|
4715
|
+
` Script hygiene: inline scripts ${report.runtimeAudit.inlineScriptCount} | inline event handlers ${report.runtimeAudit.inlineEventHandlerCount} | scripts without integrity ${report.runtimeAudit.externalScriptsWithoutIntegrityCount} | scripts missing crossorigin ${report.runtimeAudit.externalScriptsWithIntegrityMissingCrossoriginCount} | stylesheets without integrity ${report.runtimeAudit.externalStylesheetsWithoutIntegrityCount} | stylesheets missing crossorigin ${report.runtimeAudit.externalStylesheetsWithIntegrityMissingCrossoriginCount} | insecure external scripts ${report.runtimeAudit.externalScriptsWithInsecureTransportCount} | insecure external stylesheets ${report.runtimeAudit.externalStylesheetsWithInsecureTransportCount} | insecure external media ${report.runtimeAudit.externalMediaSourcesWithInsecureTransportCount} | external blank links missing rel ${report.runtimeAudit.externalBlankLinksWithoutRelCount} | external iframes missing sandbox ${report.runtimeAudit.externalIframesWithoutSandboxCount} | insecure external iframes ${report.runtimeAudit.externalIframesWithInsecureTransportCount}`
|
|
4716
|
+
);
|
|
4717
|
+
console.log(
|
|
4718
|
+
` JS risk signals: dynamic code ${report.runtimeAudit.jsEvalSignalCount} | html injection ${report.runtimeAudit.jsHtmlInjectionSignalCount} | insecure/dev transport ${report.runtimeAudit.jsInsecureTransportSignalCount} | secret markers ${report.runtimeAudit.jsSecretSignalCount}`
|
|
4719
|
+
);
|
|
4720
|
+
}
|
|
4721
|
+
console.log(` Findings: ${report.summary.errorCount} error(s), ${report.summary.warnCount} warn(s), ${report.summary.infoCount} info`);
|
|
4722
|
+
console.log("");
|
|
4723
|
+
console.log(`${BOLD6}Findings:${RESET13}`);
|
|
4724
|
+
printVerificationFindings(report.findings);
|
|
4725
|
+
}
|
|
4726
|
+
function printFileCritiqueReport(report) {
|
|
4727
|
+
console.log(success3(`Critiqued ${report.file}`));
|
|
4728
|
+
console.log("");
|
|
4729
|
+
console.log(`${BOLD6}Summary:${RESET13}`);
|
|
4730
|
+
console.log(` Overall score: ${report.overall}/5`);
|
|
4731
|
+
console.log(` Focus areas: ${report.focusAreas.join(", ")}`);
|
|
4732
|
+
console.log(` Review pack: ${report.reviewPack ? "present" : "missing"}`);
|
|
4733
|
+
console.log("");
|
|
4734
|
+
console.log(`${BOLD6}Scores:${RESET13}`);
|
|
4735
|
+
for (const score of report.scores) {
|
|
4736
|
+
console.log(` ${cyan3(score.category.padEnd(20))} ${score.score}/5 ${dim3(score.details)}`);
|
|
4737
|
+
}
|
|
4738
|
+
console.log("");
|
|
4739
|
+
console.log(`${BOLD6}Findings:${RESET13}`);
|
|
4740
|
+
printVerificationFindings(report.findings);
|
|
4741
|
+
}
|
|
4742
|
+
async function cmdAudit(filePath) {
|
|
4743
|
+
const projectRoot = process.cwd();
|
|
3976
4744
|
try {
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
console.log(
|
|
4745
|
+
if (filePath) {
|
|
4746
|
+
const hydration2 = await hydrateHostedReviewPackIfMissing(projectRoot);
|
|
4747
|
+
console.log(heading2(`Critiquing ${filePath}...`));
|
|
4748
|
+
if (hydration2.hydrated) {
|
|
4749
|
+
console.log(dim3("Hydrated missing review pack from hosted registry."));
|
|
4750
|
+
console.log("");
|
|
3983
4751
|
}
|
|
4752
|
+
const report2 = await critiqueProjectFile(filePath, projectRoot);
|
|
4753
|
+
printFileCritiqueReport(report2);
|
|
4754
|
+
if (report2.findings.some((finding) => finding.severity === "error")) {
|
|
4755
|
+
process.exitCode = 1;
|
|
4756
|
+
}
|
|
4757
|
+
return;
|
|
4758
|
+
}
|
|
4759
|
+
const hydration = await hydrateHostedExecutionPacksIfMissing(projectRoot);
|
|
4760
|
+
console.log(heading2("Auditing project..."));
|
|
4761
|
+
if (hydration.hydrated) {
|
|
4762
|
+
console.log(dim3(
|
|
4763
|
+
hydration.scope === "bundle" ? "Hydrated missing execution packs from hosted registry." : "Hydrated missing review pack and manifest from hosted registry."
|
|
4764
|
+
));
|
|
4765
|
+
console.log("");
|
|
4766
|
+
}
|
|
4767
|
+
const report = await auditProject(projectRoot);
|
|
4768
|
+
printProjectAuditReport(report);
|
|
4769
|
+
if (!report.valid) {
|
|
3984
4770
|
process.exitCode = 1;
|
|
3985
4771
|
return;
|
|
3986
4772
|
}
|
|
3987
|
-
|
|
3988
|
-
const { themeRegistry, patternRegistry } = buildRegistryContext();
|
|
3989
|
-
const violations = evaluateGuard(essence, { themeRegistry, patternRegistry });
|
|
3990
|
-
if (violations.length > 0) {
|
|
4773
|
+
if (report.findings.length > 0) {
|
|
3991
4774
|
console.log("");
|
|
3992
|
-
console.log(
|
|
3993
|
-
for (const v of violations) {
|
|
3994
|
-
const vr = v;
|
|
3995
|
-
console.log(` ${YELLOW9}[${vr.rule}]${RESET13} ${vr.message}`);
|
|
3996
|
-
if (vr.suggestion) {
|
|
3997
|
-
console.log(` ${DIM13}Suggestion: ${vr.suggestion}${RESET13}`);
|
|
3998
|
-
}
|
|
3999
|
-
}
|
|
4000
|
-
} else {
|
|
4001
|
-
console.log(success3("No guard violations."));
|
|
4775
|
+
console.log(dim3("Project audit completed with advisory findings."));
|
|
4002
4776
|
}
|
|
4003
|
-
console.log("");
|
|
4004
|
-
console.log(`${BOLD6}Summary:${RESET13}`);
|
|
4005
|
-
console.log(` Pages defined: ${essence.structure.length}`);
|
|
4006
|
-
console.log(` Guard mode: ${essence.guard.mode}`);
|
|
4007
|
-
console.log(` Theme: ${essence.theme.style}`);
|
|
4008
4777
|
} catch (e) {
|
|
4009
4778
|
console.log(`${RED11}Error: ${e.message}${RESET13}`);
|
|
4010
4779
|
process.exitCode = 1;
|
|
@@ -4047,7 +4816,7 @@ ${BOLD6}Examples:${RESET13}
|
|
|
4047
4816
|
console.log(success3(`Created custom theme "${name}"`));
|
|
4048
4817
|
console.log(dim3(` Path: ${result.path}`));
|
|
4049
4818
|
console.log("");
|
|
4050
|
-
console.log(`Use in essence: ${cyan3(`"
|
|
4819
|
+
console.log(`Use in essence: ${cyan3(`"id": "custom:${name}"`)}`);
|
|
4051
4820
|
} else {
|
|
4052
4821
|
console.error(error3(result.error || "Failed to create theme"));
|
|
4053
4822
|
process.exitCode = 1;
|
|
@@ -4074,14 +4843,14 @@ ${BOLD6}Examples:${RESET13}
|
|
|
4074
4843
|
process.exitCode = 1;
|
|
4075
4844
|
return;
|
|
4076
4845
|
}
|
|
4077
|
-
const themePath =
|
|
4078
|
-
if (!
|
|
4846
|
+
const themePath = join24(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
|
|
4847
|
+
if (!existsSync24(themePath)) {
|
|
4079
4848
|
console.error(error3(`Theme "${name}" not found at ${themePath}`));
|
|
4080
4849
|
process.exitCode = 1;
|
|
4081
4850
|
return;
|
|
4082
4851
|
}
|
|
4083
4852
|
try {
|
|
4084
|
-
const theme = JSON.parse(
|
|
4853
|
+
const theme = JSON.parse(readFileSync16(themePath, "utf-8"));
|
|
4085
4854
|
const result = validateCustomTheme(theme);
|
|
4086
4855
|
if (result.valid) {
|
|
4087
4856
|
console.log(success3(`Custom theme "${name}" is valid`));
|
|
@@ -4159,14 +4928,20 @@ ${BOLD6}Usage:${RESET13}
|
|
|
4159
4928
|
decantr init [options]
|
|
4160
4929
|
decantr status
|
|
4161
4930
|
decantr sync
|
|
4162
|
-
decantr audit
|
|
4931
|
+
decantr audit [file]
|
|
4163
4932
|
decantr migrate
|
|
4164
4933
|
decantr check
|
|
4165
4934
|
decantr sync-drift
|
|
4166
|
-
decantr search <query> [--type <type>]
|
|
4935
|
+
decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--recommended] [--source <authored|benchmark|hybrid>]
|
|
4167
4936
|
decantr suggest <query> [--type <type>]
|
|
4168
4937
|
decantr get <type> <id>
|
|
4169
|
-
decantr list <type>
|
|
4938
|
+
decantr list <type> [--sort <recommended|recent|name>] [--recommended] [--source <authored|benchmark|hybrid>]
|
|
4939
|
+
decantr showcase [manifest|shortlist|verification] [--json]
|
|
4940
|
+
decantr registry summary [--namespace <namespace>] [--json]
|
|
4941
|
+
decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context]
|
|
4942
|
+
decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]
|
|
4943
|
+
decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]
|
|
4944
|
+
decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]
|
|
4170
4945
|
decantr validate [path]
|
|
4171
4946
|
decantr theme <subcommand>
|
|
4172
4947
|
decantr create <type> <name>
|
|
@@ -4196,7 +4971,7 @@ ${BOLD6}Commands:${RESET13}
|
|
|
4196
4971
|
${cyan3("init")} Initialize Decantr in an existing project (v3 essence by default)
|
|
4197
4972
|
${cyan3("status")} Show project status, DNA axioms, and blueprint info
|
|
4198
4973
|
${cyan3("sync")} Sync registry content from API
|
|
4199
|
-
${cyan3("audit")}
|
|
4974
|
+
${cyan3("audit")} Audit the project or critique a specific file against compiled packs
|
|
4200
4975
|
${cyan3("migrate")} Migrate v2 essence to v3 format (with .v2.backup.json backup)
|
|
4201
4976
|
${cyan3("check")} Detect drift issues (validate + guard rules) [--telemetry]
|
|
4202
4977
|
${cyan3("sync-drift")} Review and resolve drift log entries
|
|
@@ -4204,6 +4979,7 @@ ${BOLD6}Commands:${RESET13}
|
|
|
4204
4979
|
${cyan3("suggest")} Suggest patterns or alternatives for a query
|
|
4205
4980
|
${cyan3("get")} Get full details of a registry item
|
|
4206
4981
|
${cyan3("list")} List items by type
|
|
4982
|
+
${cyan3("showcase")} Inspect audited showcase benchmark metadata
|
|
4207
4983
|
${cyan3("validate")} Validate essence file (v2 and v3)
|
|
4208
4984
|
${cyan3("theme")} Manage custom themes (create, list, validate, delete, import)
|
|
4209
4985
|
${cyan3("create")} Create a custom content item (pattern, theme, blueprint, etc.)
|
|
@@ -4212,7 +4988,7 @@ ${BOLD6}Commands:${RESET13}
|
|
|
4212
4988
|
${cyan3("logout")} Remove stored credentials
|
|
4213
4989
|
${cyan3("analyze")} Scan existing project and produce analysis report
|
|
4214
4990
|
${cyan3("export")} Export design tokens to framework format (shadcn, tailwind, css-vars)
|
|
4215
|
-
${cyan3("registry")} Registry management
|
|
4991
|
+
${cyan3("registry")} Registry management and intelligence summary
|
|
4216
4992
|
${cyan3("upgrade")} Check for content updates from registry
|
|
4217
4993
|
${cyan3("help")} Show this help
|
|
4218
4994
|
|
|
@@ -4222,12 +4998,24 @@ ${BOLD6}Examples:${RESET13}
|
|
|
4222
4998
|
decantr init
|
|
4223
4999
|
decantr init --blueprint=saas-dashboard --theme=luminarum --yes
|
|
4224
5000
|
decantr status
|
|
5001
|
+
decantr audit
|
|
5002
|
+
decantr audit src/pages/HomePage.tsx
|
|
4225
5003
|
decantr migrate
|
|
4226
5004
|
decantr check
|
|
4227
5005
|
decantr sync-drift
|
|
4228
5006
|
decantr search dashboard
|
|
4229
5007
|
decantr suggest leaderboard
|
|
4230
5008
|
decantr list patterns
|
|
5009
|
+
decantr showcase shortlist
|
|
5010
|
+
decantr showcase verification --json
|
|
5011
|
+
decantr registry summary --namespace @official
|
|
5012
|
+
decantr registry compile-packs decantr.essence.json --json
|
|
5013
|
+
decantr registry compile-packs decantr.essence.json --write-context
|
|
5014
|
+
decantr registry get-pack manifest --namespace @official --json
|
|
5015
|
+
decantr registry get-pack review --namespace @official --write-context
|
|
5016
|
+
decantr registry critique-file src/pages/Home.tsx --namespace @official --json
|
|
5017
|
+
decantr registry audit-project --namespace @official --json
|
|
5018
|
+
decantr registry audit-project --namespace @official --dist dist --sources src
|
|
4231
5019
|
decantr create pattern my-card
|
|
4232
5020
|
`);
|
|
4233
5021
|
}
|
|
@@ -4266,6 +5054,7 @@ async function main() {
|
|
|
4266
5054
|
theme: newOpts.theme,
|
|
4267
5055
|
mode: newOpts.mode,
|
|
4268
5056
|
shape: newOpts.shape,
|
|
5057
|
+
target: newOpts.target,
|
|
4269
5058
|
offline: newOpts.offline === true,
|
|
4270
5059
|
registry: newOpts.registry
|
|
4271
5060
|
});
|
|
@@ -4306,7 +5095,7 @@ async function main() {
|
|
|
4306
5095
|
break;
|
|
4307
5096
|
}
|
|
4308
5097
|
case "upgrade": {
|
|
4309
|
-
const { cmdUpgrade } = await import("./upgrade-
|
|
5098
|
+
const { cmdUpgrade } = await import("./upgrade-XNUAON3G.js");
|
|
4310
5099
|
const applyFlag = args.includes("--apply");
|
|
4311
5100
|
await cmdUpgrade(process.cwd(), { apply: applyFlag });
|
|
4312
5101
|
break;
|
|
@@ -4316,7 +5105,7 @@ async function main() {
|
|
|
4316
5105
|
if (command === "heal") {
|
|
4317
5106
|
console.log(`${YELLOW9}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET13}`);
|
|
4318
5107
|
}
|
|
4319
|
-
const { cmdHeal } = await import("./heal-
|
|
5108
|
+
const { cmdHeal } = await import("./heal-MURR3RVQ.js");
|
|
4320
5109
|
const telemetryFlag = args.includes("--telemetry");
|
|
4321
5110
|
await cmdHeal(process.cwd(), { telemetry: telemetryFlag });
|
|
4322
5111
|
break;
|
|
@@ -4348,19 +5137,29 @@ async function main() {
|
|
|
4348
5137
|
break;
|
|
4349
5138
|
}
|
|
4350
5139
|
case "audit": {
|
|
4351
|
-
await cmdAudit();
|
|
5140
|
+
await cmdAudit(args[1]);
|
|
4352
5141
|
break;
|
|
4353
5142
|
}
|
|
4354
5143
|
case "search": {
|
|
4355
5144
|
const query = args[1];
|
|
4356
5145
|
if (!query) {
|
|
4357
|
-
console.error(error3("Usage: decantr search <query> [--type <type>]"));
|
|
5146
|
+
console.error(error3("Usage: decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>]"));
|
|
4358
5147
|
process.exitCode = 1;
|
|
4359
5148
|
return;
|
|
4360
5149
|
}
|
|
4361
5150
|
const typeIdx = args.indexOf("--type");
|
|
4362
5151
|
const type = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
|
|
4363
|
-
|
|
5152
|
+
const sortIdx = args.indexOf("--sort");
|
|
5153
|
+
const sort = sortIdx !== -1 ? args[sortIdx + 1] : void 0;
|
|
5154
|
+
const sourceIdx = args.indexOf("--source");
|
|
5155
|
+
const intelligenceSource = sourceIdx !== -1 ? args[sourceIdx + 1] : void 0;
|
|
5156
|
+
if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
|
|
5157
|
+
console.error(error3(`Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`));
|
|
5158
|
+
process.exitCode = 1;
|
|
5159
|
+
return;
|
|
5160
|
+
}
|
|
5161
|
+
const recommended = args.includes("--recommended");
|
|
5162
|
+
await cmdSearch(query, type, sort, recommended, intelligenceSource);
|
|
4364
5163
|
break;
|
|
4365
5164
|
}
|
|
4366
5165
|
case "suggest": {
|
|
@@ -4389,11 +5188,37 @@ async function main() {
|
|
|
4389
5188
|
case "list": {
|
|
4390
5189
|
const type = args[1];
|
|
4391
5190
|
if (!type) {
|
|
4392
|
-
console.error(error3("Usage: decantr list <type>"));
|
|
5191
|
+
console.error(error3("Usage: decantr list <type> [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>]"));
|
|
4393
5192
|
process.exitCode = 1;
|
|
4394
5193
|
return;
|
|
4395
5194
|
}
|
|
4396
|
-
|
|
5195
|
+
const sortIdx = args.indexOf("--sort");
|
|
5196
|
+
const sort = sortIdx !== -1 ? args[sortIdx + 1] : void 0;
|
|
5197
|
+
const sourceIdx = args.indexOf("--source");
|
|
5198
|
+
const intelligenceSource = sourceIdx !== -1 ? args[sourceIdx + 1] : void 0;
|
|
5199
|
+
if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
|
|
5200
|
+
console.error(error3(`Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`));
|
|
5201
|
+
process.exitCode = 1;
|
|
5202
|
+
return;
|
|
5203
|
+
}
|
|
5204
|
+
const recommended = args.includes("--recommended");
|
|
5205
|
+
await cmdList(type, sort, recommended, intelligenceSource);
|
|
5206
|
+
break;
|
|
5207
|
+
}
|
|
5208
|
+
case "showcase": {
|
|
5209
|
+
const requestedView = args[1];
|
|
5210
|
+
const view = requestedView === "manifest" || requestedView === "shortlist" || requestedView === "verification" ? requestedView : "shortlist";
|
|
5211
|
+
const jsonOutput = args.includes("--json");
|
|
5212
|
+
if (requestedView && requestedView.startsWith("--")) {
|
|
5213
|
+
await printShowcaseBenchmarks("shortlist", jsonOutput);
|
|
5214
|
+
break;
|
|
5215
|
+
}
|
|
5216
|
+
if (requestedView && !["manifest", "shortlist", "verification"].includes(requestedView)) {
|
|
5217
|
+
console.error(error3("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
|
|
5218
|
+
process.exitCode = 1;
|
|
5219
|
+
break;
|
|
5220
|
+
}
|
|
5221
|
+
await printShowcaseBenchmarks(view, jsonOutput);
|
|
4397
5222
|
break;
|
|
4398
5223
|
}
|
|
4399
5224
|
case "validate": {
|
|
@@ -4469,8 +5294,72 @@ async function main() {
|
|
|
4469
5294
|
const typeIdx = args.indexOf("--type");
|
|
4470
5295
|
const mirrorType = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
|
|
4471
5296
|
await cmdRegistryMirror(process.cwd(), { type: mirrorType });
|
|
5297
|
+
} else if (subcommand === "summary") {
|
|
5298
|
+
const namespaceIdx = args.indexOf("--namespace");
|
|
5299
|
+
const namespace = namespaceIdx !== -1 ? args[namespaceIdx + 1] : void 0;
|
|
5300
|
+
const jsonOutput = args.includes("--json");
|
|
5301
|
+
await printRegistryIntelligenceSummary(namespace, jsonOutput);
|
|
5302
|
+
} else if (subcommand === "compile-packs") {
|
|
5303
|
+
const namespaceIdx = args.indexOf("--namespace");
|
|
5304
|
+
const namespace = namespaceIdx !== -1 ? args[namespaceIdx + 1] : void 0;
|
|
5305
|
+
const jsonOutput = args.includes("--json");
|
|
5306
|
+
const writeContext = args.includes("--write-context");
|
|
5307
|
+
const essencePath = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
|
|
5308
|
+
await printHostedExecutionPackBundle(essencePath, namespace, jsonOutput, writeContext);
|
|
5309
|
+
} else if (subcommand === "get-pack") {
|
|
5310
|
+
const namespaceIdx = args.indexOf("--namespace");
|
|
5311
|
+
const namespace = namespaceIdx !== -1 ? args[namespaceIdx + 1] : void 0;
|
|
5312
|
+
const jsonOutput = args.includes("--json");
|
|
5313
|
+
const writeContext = args.includes("--write-context");
|
|
5314
|
+
const essenceIdx = args.indexOf("--essence");
|
|
5315
|
+
const essencePath = essenceIdx !== -1 ? args[essenceIdx + 1] : void 0;
|
|
5316
|
+
const packType = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
|
|
5317
|
+
const id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
|
|
5318
|
+
if (!packType || !["manifest", "scaffold", "review", "section", "page", "mutation"].includes(packType)) {
|
|
5319
|
+
console.error(`${RED11}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET13}`);
|
|
5320
|
+
process.exitCode = 1;
|
|
5321
|
+
break;
|
|
5322
|
+
}
|
|
5323
|
+
if (packType === "manifest") {
|
|
5324
|
+
await printHostedExecutionPackManifest(essencePath, namespace, jsonOutput, writeContext);
|
|
5325
|
+
break;
|
|
5326
|
+
}
|
|
5327
|
+
await printHostedSelectedExecutionPack(
|
|
5328
|
+
packType,
|
|
5329
|
+
id,
|
|
5330
|
+
essencePath,
|
|
5331
|
+
namespace,
|
|
5332
|
+
jsonOutput,
|
|
5333
|
+
writeContext
|
|
5334
|
+
);
|
|
5335
|
+
} else if (subcommand === "critique-file") {
|
|
5336
|
+
const namespaceIdx = args.indexOf("--namespace");
|
|
5337
|
+
const namespace = namespaceIdx !== -1 ? args[namespaceIdx + 1] : void 0;
|
|
5338
|
+
const jsonOutput = args.includes("--json");
|
|
5339
|
+
const essenceIdx = args.indexOf("--essence");
|
|
5340
|
+
const essencePath = essenceIdx !== -1 ? args[essenceIdx + 1] : void 0;
|
|
5341
|
+
const treatmentsIdx = args.indexOf("--treatments");
|
|
5342
|
+
const treatmentsPath = treatmentsIdx !== -1 ? args[treatmentsIdx + 1] : void 0;
|
|
5343
|
+
const sourcePath = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
|
|
5344
|
+
if (!sourcePath) {
|
|
5345
|
+
console.error(`${RED11}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET13}`);
|
|
5346
|
+
process.exitCode = 1;
|
|
5347
|
+
break;
|
|
5348
|
+
}
|
|
5349
|
+
await printHostedFileCritique(sourcePath, namespace, jsonOutput, essencePath, treatmentsPath);
|
|
5350
|
+
} else if (subcommand === "audit-project") {
|
|
5351
|
+
const namespaceIdx = args.indexOf("--namespace");
|
|
5352
|
+
const namespace = namespaceIdx !== -1 ? args[namespaceIdx + 1] : void 0;
|
|
5353
|
+
const jsonOutput = args.includes("--json");
|
|
5354
|
+
const essenceIdx = args.indexOf("--essence");
|
|
5355
|
+
const essencePath = essenceIdx !== -1 ? args[essenceIdx + 1] : void 0;
|
|
5356
|
+
const distIdx = args.indexOf("--dist");
|
|
5357
|
+
const distPath = distIdx !== -1 ? args[distIdx + 1] : void 0;
|
|
5358
|
+
const sourcesIdx = args.indexOf("--sources");
|
|
5359
|
+
const sourcesPath = sourcesIdx !== -1 ? args[sourcesIdx + 1] : void 0;
|
|
5360
|
+
await printHostedProjectAudit(namespace, jsonOutput, essencePath, distPath, sourcesPath);
|
|
4472
5361
|
} else {
|
|
4473
|
-
console.error(`${RED11}Usage: decantr registry mirror [--type <type>]${RESET13}`);
|
|
5362
|
+
console.error(`${RED11}Usage: decantr registry mirror [--type <type>] | decantr registry summary [--namespace <namespace>] [--json] | decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context] | decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context] | decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>] | decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]${RESET13}`);
|
|
4474
5363
|
process.exitCode = 1;
|
|
4475
5364
|
}
|
|
4476
5365
|
break;
|