@decantr/cli 2.11.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/bin.js +4 -4
- package/dist/{chunk-4SZ4SEKT.js → chunk-CAKQWTZS.js} +67 -29
- package/dist/{chunk-NUNUW5IS.js → chunk-F6SWDGKO.js} +1 -1
- package/dist/{chunk-5WPRTVNA.js → chunk-PHRVC575.js} +4 -3
- package/dist/{chunk-ET4BG746.js → chunk-SWPAAAO4.js} +889 -423
- package/dist/{heal-2UCSPRTK.js → heal-WMSAX4LU.js} +1 -1
- package/dist/{health-ADHNLMX3.js → health-DBCUR6VQ.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{studio-GZFCCVSO.js → studio-L6JJQYCS.js} +3 -3
- package/dist/{workspace-YYCRXJNB.js → workspace-BCA5RCHN.js} +3 -3
- package/package.json +5 -5
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
listWorkspaceCandidates,
|
|
23
23
|
listWorkspaceProjects,
|
|
24
24
|
shouldFailWorkspaceHealth
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-F6SWDGKO.js";
|
|
26
26
|
import {
|
|
27
27
|
createProjectHealthReport,
|
|
28
28
|
formatProjectHealthMarkdown,
|
|
29
29
|
formatProjectHealthText,
|
|
30
30
|
resolveWorkspaceInfo,
|
|
31
31
|
shouldFailHealth
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-PHRVC575.js";
|
|
33
33
|
import {
|
|
34
34
|
buildGuardRegistryContext,
|
|
35
35
|
createDoctrineMap,
|
|
@@ -46,11 +46,11 @@ import {
|
|
|
46
46
|
sendCliCommandTelemetry,
|
|
47
47
|
sendNewProjectCompletedTelemetry,
|
|
48
48
|
writeDoctrineMap
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-CAKQWTZS.js";
|
|
50
50
|
|
|
51
51
|
// src/index.ts
|
|
52
|
-
import { existsSync as
|
|
53
|
-
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute3, join as
|
|
52
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync17, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync20 } from "fs";
|
|
53
|
+
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute3, join as join32, relative as relative7, resolve as resolve4 } from "path";
|
|
54
54
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
55
55
|
import { evaluateGuard, isV4 as isV49, validateEssence as validateEssence2 } from "@decantr/essence-spec";
|
|
56
56
|
import {
|
|
@@ -88,6 +88,7 @@ Commit these when they exist:
|
|
|
88
88
|
- \`.decantr/project.json\` - workflow, adoption mode, detection, and initialization metadata.
|
|
89
89
|
- \`.decantr/local-patterns.json\` - project-owned Brownfield UI patterns accepted by the team.
|
|
90
90
|
- \`.decantr/rules.json\` - project-owned mechanical rules accepted by the team.
|
|
91
|
+
- \`.decantr/style-bridge.json\` - accepted Hybrid style bridge from Decantr intent to project tokens/classes.
|
|
91
92
|
|
|
92
93
|
## Generated Context
|
|
93
94
|
|
|
@@ -3233,8 +3234,8 @@ ${YELLOW2}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then
|
|
|
3233
3234
|
}
|
|
3234
3235
|
|
|
3235
3236
|
// src/commands/ci.ts
|
|
3236
|
-
import { existsSync as
|
|
3237
|
-
import { dirname as dirname3, join as
|
|
3237
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
3238
|
+
import { dirname as dirname3, join as join17, relative as relative4, resolve } from "path";
|
|
3238
3239
|
|
|
3239
3240
|
// src/local-law.ts
|
|
3240
3241
|
import { execFileSync } from "child_process";
|
|
@@ -3677,10 +3678,25 @@ function collectClassHints(projectRoot, files, terms) {
|
|
|
3677
3678
|
if (!UI_TEMPLATE_EXTENSIONS.has(extname(file.absolute))) continue;
|
|
3678
3679
|
const content = readFileSync11(join15(projectRoot, file.relative), "utf-8");
|
|
3679
3680
|
if (!terms.some((term) => content.toLowerCase().includes(term))) continue;
|
|
3681
|
+
if (wantsButton) {
|
|
3682
|
+
const openingTags = content.matchAll(
|
|
3683
|
+
/<([A-Za-z][\w.:/-]*)\b[^>]*\bclass(?:Name)?\s*=\s*["'`]([^"'`]+)["'`][^>]*>/g
|
|
3684
|
+
);
|
|
3685
|
+
for (const match of openingTags) {
|
|
3686
|
+
const tag = match[1];
|
|
3687
|
+
const value = match[2].trim();
|
|
3688
|
+
const tagLooksInteractive = /^(button|a|Link)$/i.test(tag) || /(^|\.)(Button|IconButton|LinkButton|Action)$/i.test(tag);
|
|
3689
|
+
const fileLooksInteractive = /button|action|link/i.test(basename2(file.relative));
|
|
3690
|
+
if (!tagLooksInteractive && !fileLooksInteractive) continue;
|
|
3691
|
+
if (!buttonSignal.test(value) && !fileLooksInteractive) continue;
|
|
3692
|
+
hints.set(value, (hints.get(value) ?? 0) + 1);
|
|
3693
|
+
}
|
|
3694
|
+
continue;
|
|
3695
|
+
}
|
|
3680
3696
|
const matches = content.matchAll(/\bclass(?:Name)?\s*=\s*["'`]([^"'`]+)["'`]/g);
|
|
3681
3697
|
for (const match of matches) {
|
|
3682
3698
|
const value = match[1].trim();
|
|
3683
|
-
const keep =
|
|
3699
|
+
const keep = wantsSurface && surfaceSignal.test(value) || !wantsButton && !wantsSurface && (buttonSignal.test(value) || surfaceSignal.test(value));
|
|
3684
3700
|
if (!keep) continue;
|
|
3685
3701
|
hints.set(value, (hints.get(value) ?? 0) + 1);
|
|
3686
3702
|
}
|
|
@@ -3748,6 +3764,277 @@ function lineAt(contents, line) {
|
|
|
3748
3764
|
return contents.split(/\r?\n/)[line - 1] ?? "";
|
|
3749
3765
|
}
|
|
3750
3766
|
|
|
3767
|
+
// src/style-bridge.ts
|
|
3768
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
3769
|
+
import { join as join16 } from "path";
|
|
3770
|
+
function styleBridgeProposalPath(projectRoot) {
|
|
3771
|
+
return join16(projectRoot, ".decantr", "style-bridge.proposal.json");
|
|
3772
|
+
}
|
|
3773
|
+
function styleBridgePath(projectRoot) {
|
|
3774
|
+
return join16(projectRoot, ".decantr", "style-bridge.json");
|
|
3775
|
+
}
|
|
3776
|
+
function readJsonFile2(path) {
|
|
3777
|
+
if (!existsSync14(path)) return null;
|
|
3778
|
+
try {
|
|
3779
|
+
return JSON.parse(readFileSync12(path, "utf-8"));
|
|
3780
|
+
} catch {
|
|
3781
|
+
return null;
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
function writeJsonFile(path, value) {
|
|
3785
|
+
writeFileSync10(path, `${JSON.stringify(value, null, 2)}
|
|
3786
|
+
`, "utf-8");
|
|
3787
|
+
}
|
|
3788
|
+
function readStyleBridge(projectRoot) {
|
|
3789
|
+
return readJsonFile2(styleBridgePath(projectRoot));
|
|
3790
|
+
}
|
|
3791
|
+
function readStyleBridgeProposal(projectRoot) {
|
|
3792
|
+
return readJsonFile2(styleBridgeProposalPath(projectRoot));
|
|
3793
|
+
}
|
|
3794
|
+
function stringArray(value) {
|
|
3795
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
3796
|
+
}
|
|
3797
|
+
function readThemeInventory(projectRoot) {
|
|
3798
|
+
const inventory = readJsonFile2(join16(projectRoot, ".decantr", "theme-inventory.json"));
|
|
3799
|
+
return {
|
|
3800
|
+
modes: stringArray(inventory?.modes),
|
|
3801
|
+
variantIds: Array.isArray(inventory?.variants) ? inventory.variants.map((variant) => variant.id).filter((id) => typeof id === "string") : [],
|
|
3802
|
+
darkModeDetected: typeof inventory?.darkModeDetected === "boolean" ? inventory.darkModeDetected : null
|
|
3803
|
+
};
|
|
3804
|
+
}
|
|
3805
|
+
function tokenHints(styling, terms) {
|
|
3806
|
+
return styling.cssVariables.filter((name) => terms.test(name)).slice(0, 12);
|
|
3807
|
+
}
|
|
3808
|
+
function readProjectPatternPack(projectRoot) {
|
|
3809
|
+
return readLocalPatternPack(projectRoot) ?? readJsonFile2(
|
|
3810
|
+
join16(projectRoot, ".decantr", "local-patterns.proposal.json")
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3813
|
+
function classHintsForPattern(projectRoot, ids) {
|
|
3814
|
+
const pack = readProjectPatternPack(projectRoot);
|
|
3815
|
+
const classes = /* @__PURE__ */ new Set();
|
|
3816
|
+
for (const pattern of pack?.patterns ?? []) {
|
|
3817
|
+
if (!ids.includes(String(pattern.id))) continue;
|
|
3818
|
+
for (const hint of pattern.classHints ?? []) classes.add(hint);
|
|
3819
|
+
}
|
|
3820
|
+
return [...classes].slice(0, 12);
|
|
3821
|
+
}
|
|
3822
|
+
function sourceEvidence(projectRoot, ids) {
|
|
3823
|
+
const pack = readProjectPatternPack(projectRoot);
|
|
3824
|
+
const evidence = /* @__PURE__ */ new Set();
|
|
3825
|
+
for (const pattern of pack?.patterns ?? []) {
|
|
3826
|
+
if (!ids.includes(String(pattern.id))) continue;
|
|
3827
|
+
for (const path of pattern.componentPaths ?? []) evidence.add(path);
|
|
3828
|
+
for (const item of pattern.evidence ?? []) evidence.add(item);
|
|
3829
|
+
}
|
|
3830
|
+
return [...evidence].slice(0, 12);
|
|
3831
|
+
}
|
|
3832
|
+
function colorTokenNames(styling) {
|
|
3833
|
+
const names = new Set(Object.keys(styling.colors ?? {}));
|
|
3834
|
+
for (const variable of styling.cssVariables) {
|
|
3835
|
+
if (/color|bg|background|surface|text|foreground|border|primary|secondary|accent|muted/i.test(variable)) {
|
|
3836
|
+
names.add(variable);
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
return [...names].slice(0, 40);
|
|
3840
|
+
}
|
|
3841
|
+
function createStyleBridgeProposal(input) {
|
|
3842
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3843
|
+
const theme = readThemeInventory(input.projectRoot);
|
|
3844
|
+
const routeCount = input.essence && typeof input.essence === "object" && "blueprint" in input.essence ? Object.keys(input.essence.blueprint?.routes ?? {}).length : 0;
|
|
3845
|
+
const target = input.essence && typeof input.essence === "object" && "meta" in input.essence ? String(input.essence.meta?.target ?? "") || null : null;
|
|
3846
|
+
const darkModeDetected = theme.darkModeDetected ?? input.styling.darkMode;
|
|
3847
|
+
const themeModes = theme.modes.length > 0 ? theme.modes : darkModeDetected ? ["base", "dark"] : ["base"];
|
|
3848
|
+
const themeVariantIds = theme.variantIds.length > 0 ? theme.variantIds : themeModes.filter((mode) => mode !== "base");
|
|
3849
|
+
return {
|
|
3850
|
+
version: 1,
|
|
3851
|
+
status: "proposal",
|
|
3852
|
+
generatedAt,
|
|
3853
|
+
source: "decantr codify --style-bridge",
|
|
3854
|
+
purpose: "Project-owned Hybrid style bridge. It maps Decantr design intent to the existing app styling system without installing Decantr CSS or taking over source.",
|
|
3855
|
+
adoption: {
|
|
3856
|
+
mode: "style-bridge",
|
|
3857
|
+
workflowMode: "brownfield-attach",
|
|
3858
|
+
sourceAuthority: "Existing production source stays authoritative.",
|
|
3859
|
+
styleAuthority: "Use these mappings to translate Decantr concepts into project-owned tokens, classes, and components.",
|
|
3860
|
+
notRuntimeTakeover: true,
|
|
3861
|
+
authorityPrecedence: [
|
|
3862
|
+
"existing production source",
|
|
3863
|
+
"accepted style bridge",
|
|
3864
|
+
"accepted local patterns and rules",
|
|
3865
|
+
"Essence V4 contract",
|
|
3866
|
+
"hosted registry patterns and execution packs as optional guidance"
|
|
3867
|
+
]
|
|
3868
|
+
},
|
|
3869
|
+
project: {
|
|
3870
|
+
framework: input.detected.framework,
|
|
3871
|
+
packageManager: input.detected.packageManager,
|
|
3872
|
+
target,
|
|
3873
|
+
routeCount
|
|
3874
|
+
},
|
|
3875
|
+
styling: {
|
|
3876
|
+
approach: input.styling.approach,
|
|
3877
|
+
configFile: input.styling.configFile ?? null,
|
|
3878
|
+
darkModeDetected,
|
|
3879
|
+
cssVariables: input.styling.cssVariables.slice(0, 80),
|
|
3880
|
+
colorTokenNames: colorTokenNames(input.styling),
|
|
3881
|
+
themeModes,
|
|
3882
|
+
themeVariantIds
|
|
3883
|
+
},
|
|
3884
|
+
mappings: [
|
|
3885
|
+
{
|
|
3886
|
+
id: "surface",
|
|
3887
|
+
label: "Surfaces and cards",
|
|
3888
|
+
decantrIntent: "surface background, card treatment, border, radius, depth, and hover state",
|
|
3889
|
+
projectAuthority: "Use the app card/surface primitives, tokens, and accepted local law.",
|
|
3890
|
+
tokenHints: tokenHints(input.styling, /surface|card|panel|bg|background|border|shadow|radius/i),
|
|
3891
|
+
classHints: classHintsForPattern(input.projectRoot, ["surface-card"]),
|
|
3892
|
+
sourceEvidence: sourceEvidence(input.projectRoot, ["surface-card"]),
|
|
3893
|
+
guardrails: [
|
|
3894
|
+
"Do not invent a new card color/radius/shadow recipe without updating local law.",
|
|
3895
|
+
"Do not add Decantr CSS d-* classes unless adoption mode changes to decantr-css."
|
|
3896
|
+
]
|
|
3897
|
+
},
|
|
3898
|
+
{
|
|
3899
|
+
id: "action",
|
|
3900
|
+
label: "Actions and buttons",
|
|
3901
|
+
decantrIntent: "primary, secondary, tertiary, destructive, icon-only, loading, and disabled action states",
|
|
3902
|
+
projectAuthority: "Use the app button/action primitives and local variant names.",
|
|
3903
|
+
tokenHints: tokenHints(input.styling, /primary|secondary|accent|danger|error|destructive|focus/i),
|
|
3904
|
+
classHints: classHintsForPattern(input.projectRoot, ["button"]),
|
|
3905
|
+
sourceEvidence: sourceEvidence(input.projectRoot, ["button"]),
|
|
3906
|
+
guardrails: [
|
|
3907
|
+
"Map any new action style to primary/secondary/tertiary/destructive/icon before coding.",
|
|
3908
|
+
"Avoid raw button markup when a project-owned primitive exists."
|
|
3909
|
+
]
|
|
3910
|
+
},
|
|
3911
|
+
{
|
|
3912
|
+
id: "focus-accessibility",
|
|
3913
|
+
label: "Focus and accessibility",
|
|
3914
|
+
decantrIntent: "visible focus, keyboard clarity, contrast, and reduced-motion safety",
|
|
3915
|
+
projectAuthority: "Use the app accessibility classes, focus tokens, and framework conventions.",
|
|
3916
|
+
tokenHints: tokenHints(input.styling, /focus|ring|outline|contrast|motion|duration/i),
|
|
3917
|
+
classHints: [],
|
|
3918
|
+
sourceEvidence: [],
|
|
3919
|
+
guardrails: [
|
|
3920
|
+
"Every new interactive control needs visible focus evidence.",
|
|
3921
|
+
"Motion should honor prefers-reduced-motion or an existing app motion helper."
|
|
3922
|
+
]
|
|
3923
|
+
},
|
|
3924
|
+
{
|
|
3925
|
+
id: "layout-density",
|
|
3926
|
+
label: "Layout density and spacing",
|
|
3927
|
+
decantrIntent: "route gutters, section gaps, component padding, density, and responsive rhythm",
|
|
3928
|
+
projectAuthority: "Use existing layout wrappers, shell primitives, and spacing tokens/classes.",
|
|
3929
|
+
tokenHints: tokenHints(input.styling, /space|spacing|gap|gutter|container|radius/i),
|
|
3930
|
+
classHints: classHintsForPattern(input.projectRoot, ["page-shell"]),
|
|
3931
|
+
sourceEvidence: sourceEvidence(input.projectRoot, ["page-shell"]),
|
|
3932
|
+
guardrails: [
|
|
3933
|
+
"Do not let each page invent independent max-width, gutters, or scroll ownership.",
|
|
3934
|
+
"Use the detected shell/layout authority before adding a new wrapper."
|
|
3935
|
+
]
|
|
3936
|
+
},
|
|
3937
|
+
{
|
|
3938
|
+
id: "theme-variant",
|
|
3939
|
+
label: "Theme variants",
|
|
3940
|
+
decantrIntent: "light, dark, brand, tenant, seasonal, and density variants",
|
|
3941
|
+
projectAuthority: "Use the app theme provider, data attributes, CSS variables, or Tailwind mode strategy.",
|
|
3942
|
+
tokenHints: tokenHints(input.styling, /theme|dark|light|brand|tenant|mode|color/i),
|
|
3943
|
+
classHints: classHintsForPattern(input.projectRoot, ["theme-variant"]),
|
|
3944
|
+
sourceEvidence: sourceEvidence(input.projectRoot, ["theme-variant"]),
|
|
3945
|
+
guardrails: [
|
|
3946
|
+
"Keep theme modes documented in .decantr/theme-inventory.json and this bridge.",
|
|
3947
|
+
"Do not treat theme switcher container classes as standalone theme variants."
|
|
3948
|
+
]
|
|
3949
|
+
}
|
|
3950
|
+
],
|
|
3951
|
+
rules: [
|
|
3952
|
+
"The bridge is advisory until accepted; after acceptance, task/doctor/CI should surface it as Hybrid authority.",
|
|
3953
|
+
"The bridge does not make hosted registry patterns enforceable. Map hosted concepts into local law first.",
|
|
3954
|
+
"Keep deterministic blocking checks in .decantr/rules.json, ESLint, Biome, tests, or visual regression."
|
|
3955
|
+
],
|
|
3956
|
+
nextSteps: [
|
|
3957
|
+
"Review token and class hints. Replace generic hints with the exact project tokens/classes the team owns.",
|
|
3958
|
+
"Run decantr codify --accept to promote the proposal to .decantr/style-bridge.json.",
|
|
3959
|
+
"Use decantr task <route> before LLM edits so the style bridge appears in task context.",
|
|
3960
|
+
"Run decantr ci or decantr verify after edits to keep local law and Project Health visible."
|
|
3961
|
+
]
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
function writeStyleBridgeProposal(projectRoot, proposal) {
|
|
3965
|
+
const decantrDir = join16(projectRoot, ".decantr");
|
|
3966
|
+
mkdirSync9(decantrDir, { recursive: true });
|
|
3967
|
+
const path = styleBridgeProposalPath(projectRoot);
|
|
3968
|
+
writeJsonFile(path, proposal);
|
|
3969
|
+
return path;
|
|
3970
|
+
}
|
|
3971
|
+
function acceptStyleBridge(projectRoot) {
|
|
3972
|
+
const proposal = readStyleBridgeProposal(projectRoot);
|
|
3973
|
+
if (!proposal) return null;
|
|
3974
|
+
const accepted = {
|
|
3975
|
+
...proposal,
|
|
3976
|
+
status: "accepted",
|
|
3977
|
+
acceptedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3978
|
+
};
|
|
3979
|
+
const path = styleBridgePath(projectRoot);
|
|
3980
|
+
writeJsonFile(path, accepted);
|
|
3981
|
+
const projectJsonPath = join16(projectRoot, ".decantr", "project.json");
|
|
3982
|
+
const projectJson = readJsonFile2(projectJsonPath) ?? {};
|
|
3983
|
+
const initialized = typeof projectJson.initialized === "object" && projectJson.initialized !== null ? projectJson.initialized : {};
|
|
3984
|
+
writeJsonFile(projectJsonPath, {
|
|
3985
|
+
...projectJson,
|
|
3986
|
+
initialized: {
|
|
3987
|
+
...initialized,
|
|
3988
|
+
workflowMode: initialized.workflowMode ?? "brownfield-attach",
|
|
3989
|
+
adoptionMode: "style-bridge"
|
|
3990
|
+
}
|
|
3991
|
+
});
|
|
3992
|
+
return path;
|
|
3993
|
+
}
|
|
3994
|
+
function createStyleBridgeTaskSummary(projectRoot) {
|
|
3995
|
+
const bridge = readStyleBridge(projectRoot);
|
|
3996
|
+
return {
|
|
3997
|
+
path: bridge ? ".decantr/style-bridge.json" : null,
|
|
3998
|
+
status: bridge?.status ?? null,
|
|
3999
|
+
mappingCount: bridge?.mappings?.length ?? 0,
|
|
4000
|
+
stylingApproach: bridge?.styling?.approach ?? null,
|
|
4001
|
+
themeModes: bridge?.styling?.themeModes ?? [],
|
|
4002
|
+
mappings: bridge?.mappings?.map((mapping) => ({
|
|
4003
|
+
id: mapping.id,
|
|
4004
|
+
label: mapping.label,
|
|
4005
|
+
tokenHints: mapping.tokenHints.slice(0, 6),
|
|
4006
|
+
classHints: mapping.classHints.slice(0, 4),
|
|
4007
|
+
guardrails: mapping.guardrails.slice(0, 3)
|
|
4008
|
+
})) ?? []
|
|
4009
|
+
};
|
|
4010
|
+
}
|
|
4011
|
+
function styleBridgeMatches(projectRoot, query) {
|
|
4012
|
+
if (!projectRoot) return [];
|
|
4013
|
+
const bridge = readStyleBridge(projectRoot);
|
|
4014
|
+
if (!bridge) return [];
|
|
4015
|
+
const terms = query.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1).flatMap((term) => term.endsWith("s") && term.length > 3 ? [term, term.slice(0, -1)] : [term]);
|
|
4016
|
+
if (terms.length === 0) return [];
|
|
4017
|
+
return bridge.mappings.map((mapping) => {
|
|
4018
|
+
const haystack = [
|
|
4019
|
+
mapping.id,
|
|
4020
|
+
mapping.label,
|
|
4021
|
+
mapping.decantrIntent,
|
|
4022
|
+
mapping.projectAuthority,
|
|
4023
|
+
...mapping.tokenHints,
|
|
4024
|
+
...mapping.classHints,
|
|
4025
|
+
...mapping.guardrails
|
|
4026
|
+
].join(" ").toLowerCase();
|
|
4027
|
+
const score = terms.reduce((sum, term) => sum + (haystack.includes(term) ? 1 : 0), 0);
|
|
4028
|
+
return {
|
|
4029
|
+
id: mapping.id,
|
|
4030
|
+
label: mapping.label,
|
|
4031
|
+
score,
|
|
4032
|
+
tokenHints: mapping.tokenHints.slice(0, 4),
|
|
4033
|
+
classHints: mapping.classHints.slice(0, 3)
|
|
4034
|
+
};
|
|
4035
|
+
}).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, 5);
|
|
4036
|
+
}
|
|
4037
|
+
|
|
3751
4038
|
// src/commands/ci.ts
|
|
3752
4039
|
var BOLD2 = "\x1B[1m";
|
|
3753
4040
|
var DIM3 = "\x1B[2m";
|
|
@@ -3756,9 +4043,9 @@ var RED2 = "\x1B[31m";
|
|
|
3756
4043
|
var RESET3 = "\x1B[0m";
|
|
3757
4044
|
var CI_SCHEMA = "https://decantr.ai/schemas/decantr-ci-report.v1.json";
|
|
3758
4045
|
function readJson(path) {
|
|
3759
|
-
if (!
|
|
4046
|
+
if (!existsSync15(path)) return null;
|
|
3760
4047
|
try {
|
|
3761
|
-
return JSON.parse(
|
|
4048
|
+
return JSON.parse(readFileSync13(path, "utf-8"));
|
|
3762
4049
|
} catch {
|
|
3763
4050
|
return null;
|
|
3764
4051
|
}
|
|
@@ -3802,21 +4089,21 @@ function parseProvider(value) {
|
|
|
3802
4089
|
throw new Error("Invalid --provider value. Use github or generic.");
|
|
3803
4090
|
}
|
|
3804
4091
|
function detectPackageManager2(root) {
|
|
3805
|
-
const pkg = readJson(
|
|
4092
|
+
const pkg = readJson(join17(root, "package.json"));
|
|
3806
4093
|
const declared = pkg?.packageManager?.split("@")[0];
|
|
3807
4094
|
if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
|
|
3808
4095
|
return declared;
|
|
3809
4096
|
}
|
|
3810
|
-
if (
|
|
3811
|
-
if (
|
|
3812
|
-
if (
|
|
3813
|
-
if (
|
|
4097
|
+
if (existsSync15(join17(root, "pnpm-lock.yaml"))) return "pnpm";
|
|
4098
|
+
if (existsSync15(join17(root, "package-lock.json"))) return "npm";
|
|
4099
|
+
if (existsSync15(join17(root, "yarn.lock"))) return "yarn";
|
|
4100
|
+
if (existsSync15(join17(root, "bun.lock")) || existsSync15(join17(root, "bun.lockb"))) return "bun";
|
|
3814
4101
|
return "unknown";
|
|
3815
4102
|
}
|
|
3816
4103
|
function hasWorkspaceMarker(root) {
|
|
3817
|
-
const pkg = readJson(
|
|
4104
|
+
const pkg = readJson(join17(root, "package.json"));
|
|
3818
4105
|
return Boolean(
|
|
3819
|
-
|
|
4106
|
+
existsSync15(join17(root, "pnpm-workspace.yaml")) || existsSync15(join17(root, "turbo.json")) || existsSync15(join17(root, "nx.json")) || pkg?.workspaces
|
|
3820
4107
|
);
|
|
3821
4108
|
}
|
|
3822
4109
|
function installCommand(packageManager) {
|
|
@@ -3862,7 +4149,7 @@ function decantrCommand(packageManager) {
|
|
|
3862
4149
|
}
|
|
3863
4150
|
}
|
|
3864
4151
|
function localCliPinned(root) {
|
|
3865
|
-
const pkg = readJson(
|
|
4152
|
+
const pkg = readJson(join17(root, "package.json"));
|
|
3866
4153
|
return Boolean(pkg?.devDependencies?.["@decantr/cli"] || pkg?.dependencies?.["@decantr/cli"]);
|
|
3867
4154
|
}
|
|
3868
4155
|
function projectSlug(projectPath) {
|
|
@@ -3870,8 +4157,8 @@ function projectSlug(projectPath) {
|
|
|
3870
4157
|
}
|
|
3871
4158
|
function writeOutput(root, path, content) {
|
|
3872
4159
|
const absolute = resolve(root, path);
|
|
3873
|
-
|
|
3874
|
-
|
|
4160
|
+
mkdirSync10(dirname3(absolute), { recursive: true });
|
|
4161
|
+
writeFileSync11(absolute, content, "utf-8");
|
|
3875
4162
|
}
|
|
3876
4163
|
function summarizeLocalLaw(projectRoot) {
|
|
3877
4164
|
const validation = validateLocalLaw(projectRoot);
|
|
@@ -3893,14 +4180,36 @@ function summarizeLocalLaw(projectRoot) {
|
|
|
3893
4180
|
warnCount: validation.findings.filter((finding) => finding.severity === "warn").length + validation.warnings.length
|
|
3894
4181
|
};
|
|
3895
4182
|
}
|
|
4183
|
+
function summarizeStyleBridge(projectRoot) {
|
|
4184
|
+
const summary = createStyleBridgeTaskSummary(projectRoot);
|
|
4185
|
+
const warnings = [];
|
|
4186
|
+
if (summary.path && summary.mappingCount === 0) {
|
|
4187
|
+
warnings.push(".decantr/style-bridge.json has no mappings.");
|
|
4188
|
+
}
|
|
4189
|
+
return {
|
|
4190
|
+
checked: Boolean(summary.path),
|
|
4191
|
+
present: Boolean(summary.path),
|
|
4192
|
+
status: summary.status,
|
|
4193
|
+
mappingCount: summary.mappingCount,
|
|
4194
|
+
stylingApproach: summary.stylingApproach,
|
|
4195
|
+
themeModes: summary.themeModes,
|
|
4196
|
+
warnings
|
|
4197
|
+
};
|
|
4198
|
+
}
|
|
3896
4199
|
function localLawFails(summary, failOn) {
|
|
3897
4200
|
if (failOn === "none" || !summary.checked) return false;
|
|
3898
4201
|
if (summary.errorCount > 0) return true;
|
|
3899
4202
|
return failOn === "warn" && summary.warnCount > 0;
|
|
3900
4203
|
}
|
|
3901
|
-
function
|
|
4204
|
+
function styleBridgeFails(summary, failOn) {
|
|
4205
|
+
if (failOn === "none" || !summary.checked) return false;
|
|
4206
|
+
return failOn === "warn" && summary.warnings.length > 0;
|
|
4207
|
+
}
|
|
4208
|
+
function projectCiStatus(health, localLaw, styleBridge) {
|
|
3902
4209
|
if (health.status === "error" || localLaw.errorCount > 0) return "error";
|
|
3903
|
-
if (health.status === "warning" || localLaw.warnCount > 0)
|
|
4210
|
+
if (health.status === "warning" || localLaw.warnCount > 0 || styleBridge.warnings.length > 0) {
|
|
4211
|
+
return "warning";
|
|
4212
|
+
}
|
|
3904
4213
|
return health.status;
|
|
3905
4214
|
}
|
|
3906
4215
|
function formatLocalLawText(summary, health) {
|
|
@@ -3933,6 +4242,25 @@ function formatLocalLawText(summary, health) {
|
|
|
3933
4242
|
return `${lines.join("\n")}
|
|
3934
4243
|
`;
|
|
3935
4244
|
}
|
|
4245
|
+
function formatStyleBridgeText(summary) {
|
|
4246
|
+
const lines = ["", `${BOLD2}Project-owned style bridge:${RESET3}`];
|
|
4247
|
+
if (!summary.checked) {
|
|
4248
|
+
lines.push(" Not active for this project.");
|
|
4249
|
+
return `${lines.join("\n")}
|
|
4250
|
+
`;
|
|
4251
|
+
}
|
|
4252
|
+
lines.push(
|
|
4253
|
+
` Present: ${summary.present ? "yes" : "no"} | Mappings: ${summary.mappingCount} | Styling: ${summary.stylingApproach ?? "unknown"}`
|
|
4254
|
+
);
|
|
4255
|
+
if (summary.themeModes.length > 0) {
|
|
4256
|
+
lines.push(` Theme modes: ${summary.themeModes.join(", ")}`);
|
|
4257
|
+
}
|
|
4258
|
+
for (const warning of summary.warnings.slice(0, 5)) {
|
|
4259
|
+
lines.push(` ${DIM3}[WARN] ${warning}${RESET3}`);
|
|
4260
|
+
}
|
|
4261
|
+
return `${lines.join("\n")}
|
|
4262
|
+
`;
|
|
4263
|
+
}
|
|
3936
4264
|
function formatLocalLawMarkdown(summary, health) {
|
|
3937
4265
|
const lines = ["## Project-Owned Local Law", ""];
|
|
3938
4266
|
if (!summary.checked) {
|
|
@@ -3966,6 +4294,26 @@ function formatLocalLawMarkdown(summary, health) {
|
|
|
3966
4294
|
}
|
|
3967
4295
|
return lines.join("\n");
|
|
3968
4296
|
}
|
|
4297
|
+
function formatStyleBridgeMarkdown(summary) {
|
|
4298
|
+
const lines = ["## Project-Owned Style Bridge", ""];
|
|
4299
|
+
if (!summary.checked) {
|
|
4300
|
+
lines.push("Style bridge is not active for this project.");
|
|
4301
|
+
return lines.join("\n");
|
|
4302
|
+
}
|
|
4303
|
+
lines.push(
|
|
4304
|
+
`Present: **${summary.present ? "yes" : "no"}** \xB7 Mappings: **${summary.mappingCount}** \xB7 Styling: **${summary.stylingApproach ?? "unknown"}**`
|
|
4305
|
+
);
|
|
4306
|
+
if (summary.themeModes.length > 0) {
|
|
4307
|
+
lines.push("", `Theme modes: ${summary.themeModes.map((mode) => `\`${mode}\``).join(", ")}`);
|
|
4308
|
+
}
|
|
4309
|
+
if (summary.warnings.length > 0) {
|
|
4310
|
+
lines.push("");
|
|
4311
|
+
for (const warning of summary.warnings.slice(0, 5)) {
|
|
4312
|
+
lines.push(`- Warning: ${warning}`);
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
return lines.join("\n");
|
|
4316
|
+
}
|
|
3969
4317
|
function formatProjectCiMarkdown(report) {
|
|
3970
4318
|
const lines = [
|
|
3971
4319
|
"# Decantr CI",
|
|
@@ -3975,10 +4323,13 @@ function formatProjectCiMarkdown(report) {
|
|
|
3975
4323
|
`- Status: **${report.status}**`,
|
|
3976
4324
|
`- Fail on: \`${report.failOn}\``,
|
|
3977
4325
|
`- Local law: ${report.localLaw.checked ? `${report.localLaw.errorCount} error(s), ${report.localLaw.warnCount} warning(s)` : "not accepted yet"}`,
|
|
4326
|
+
`- Style bridge: ${report.styleBridge.checked ? `${report.styleBridge.mappingCount} mapping(s)` : "not active"}`,
|
|
3978
4327
|
"",
|
|
3979
4328
|
formatProjectHealthMarkdown(report.health),
|
|
3980
4329
|
"",
|
|
3981
|
-
formatLocalLawMarkdown(report.localLaw, report.health)
|
|
4330
|
+
formatLocalLawMarkdown(report.localLaw, report.health),
|
|
4331
|
+
"",
|
|
4332
|
+
formatStyleBridgeMarkdown(report.styleBridge)
|
|
3982
4333
|
];
|
|
3983
4334
|
return `${lines.join("\n")}
|
|
3984
4335
|
`;
|
|
@@ -4069,7 +4420,7 @@ jobs:
|
|
|
4069
4420
|
}
|
|
4070
4421
|
function writeCiInit(root, options) {
|
|
4071
4422
|
const workspaceInfo = resolveWorkspaceInfo(root, options.project);
|
|
4072
|
-
if (options.project && !
|
|
4423
|
+
if (options.project && !existsSync15(workspaceInfo.appRoot)) {
|
|
4073
4424
|
throw new Error(`Project path does not exist: ${options.project}`);
|
|
4074
4425
|
}
|
|
4075
4426
|
if (workspaceInfo.requiresProjectSelection && !options.workspace) {
|
|
@@ -4092,7 +4443,7 @@ function writeCiInit(root, options) {
|
|
|
4092
4443
|
if (provider === "generic") {
|
|
4093
4444
|
const path2 = ".decantr/ci/decantr-ci.sh";
|
|
4094
4445
|
const absolute2 = resolve(outputRoot, path2);
|
|
4095
|
-
if (
|
|
4446
|
+
if (existsSync15(absolute2) && !options.force) {
|
|
4096
4447
|
throw new Error(`${path2} already exists. Re-run with --force to replace it.`);
|
|
4097
4448
|
}
|
|
4098
4449
|
writeOutput(
|
|
@@ -4113,7 +4464,7 @@ function writeCiInit(root, options) {
|
|
|
4113
4464
|
}
|
|
4114
4465
|
const path = ".github/workflows/decantr-ci.yml";
|
|
4115
4466
|
const absolute = resolve(outputRoot, path);
|
|
4116
|
-
if (
|
|
4467
|
+
if (existsSync15(absolute) && !options.force) {
|
|
4117
4468
|
throw new Error(`${path} already exists. Re-run with --force to replace it.`);
|
|
4118
4469
|
}
|
|
4119
4470
|
writeOutput(
|
|
@@ -4162,7 +4513,7 @@ async function runWorkspaceCi(root, options) {
|
|
|
4162
4513
|
}
|
|
4163
4514
|
async function runProjectCi(root, options) {
|
|
4164
4515
|
const workspaceInfo = resolveWorkspaceInfo(root, options.project);
|
|
4165
|
-
if (options.project && !
|
|
4516
|
+
if (options.project && !existsSync15(workspaceInfo.appRoot)) {
|
|
4166
4517
|
console.error(`${RED2}Project path does not exist: ${options.project}${RESET3}`);
|
|
4167
4518
|
return 1;
|
|
4168
4519
|
}
|
|
@@ -4175,6 +4526,7 @@ async function runProjectCi(root, options) {
|
|
|
4175
4526
|
const failOn = options.failOn ?? "error";
|
|
4176
4527
|
const health = await createProjectHealthReport(workspaceInfo.appRoot);
|
|
4177
4528
|
const localLaw = summarizeLocalLaw(workspaceInfo.appRoot);
|
|
4529
|
+
const styleBridge = summarizeStyleBridge(workspaceInfo.appRoot);
|
|
4178
4530
|
const projectPath = workspaceInfo.appRoot === workspaceInfo.workspaceRoot ? null : workspaceInfo.appRoot.replace(`${workspaceInfo.workspaceRoot}/`, "");
|
|
4179
4531
|
const report = {
|
|
4180
4532
|
$schema: CI_SCHEMA,
|
|
@@ -4182,9 +4534,10 @@ async function runProjectCi(root, options) {
|
|
|
4182
4534
|
mode: "project",
|
|
4183
4535
|
projectPath,
|
|
4184
4536
|
failOn,
|
|
4185
|
-
status: projectCiStatus(health, localLaw),
|
|
4537
|
+
status: projectCiStatus(health, localLaw, styleBridge),
|
|
4186
4538
|
health,
|
|
4187
|
-
localLaw
|
|
4539
|
+
localLaw,
|
|
4540
|
+
styleBridge
|
|
4188
4541
|
};
|
|
4189
4542
|
const json = `${JSON.stringify(report, null, 2)}
|
|
4190
4543
|
`;
|
|
@@ -4195,9 +4548,11 @@ async function runProjectCi(root, options) {
|
|
|
4195
4548
|
if (options.json) process.stdout.write(json);
|
|
4196
4549
|
else if (options.markdown) process.stdout.write(markdown);
|
|
4197
4550
|
else
|
|
4198
|
-
process.stdout.write(
|
|
4551
|
+
process.stdout.write(
|
|
4552
|
+
`${formatProjectHealthText(health)}${formatLocalLawText(localLaw, health)}${formatStyleBridgeText(styleBridge)}`
|
|
4553
|
+
);
|
|
4199
4554
|
}
|
|
4200
|
-
return shouldFailHealth(health, failOn) || localLawFails(localLaw, failOn) ? 1 : 0;
|
|
4555
|
+
return shouldFailHealth(health, failOn) || localLawFails(localLaw, failOn) || styleBridgeFails(styleBridge, failOn) ? 1 : 0;
|
|
4201
4556
|
}
|
|
4202
4557
|
function cmdCiHelp() {
|
|
4203
4558
|
console.log(`
|
|
@@ -4232,8 +4587,8 @@ async function cmdCi(args = ["ci"], root = process.cwd()) {
|
|
|
4232
4587
|
}
|
|
4233
4588
|
|
|
4234
4589
|
// src/commands/create.ts
|
|
4235
|
-
import { existsSync as
|
|
4236
|
-
import { join as
|
|
4590
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync12 } from "fs";
|
|
4591
|
+
import { join as join18 } from "path";
|
|
4237
4592
|
import {
|
|
4238
4593
|
CONTENT_TYPE_TO_API_CONTENT_TYPE,
|
|
4239
4594
|
CONTENT_TYPES
|
|
@@ -4429,23 +4784,23 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
|
|
|
4429
4784
|
}
|
|
4430
4785
|
const contentType = type;
|
|
4431
4786
|
const plural = PLURAL[contentType];
|
|
4432
|
-
const customDir =
|
|
4433
|
-
const filePath =
|
|
4434
|
-
if (
|
|
4787
|
+
const customDir = join18(projectRoot, ".decantr", "custom", plural);
|
|
4788
|
+
const filePath = join18(customDir, `${name}.json`);
|
|
4789
|
+
if (existsSync16(filePath)) {
|
|
4435
4790
|
console.error(`${type} "${name}" already exists at ${filePath}`);
|
|
4436
4791
|
process.exitCode = 1;
|
|
4437
4792
|
return;
|
|
4438
4793
|
}
|
|
4439
|
-
|
|
4794
|
+
mkdirSync11(customDir, { recursive: true });
|
|
4440
4795
|
const skeleton = getSkeleton(contentType, name, humanizeId(name));
|
|
4441
|
-
|
|
4796
|
+
writeFileSync12(filePath, JSON.stringify(skeleton, null, 2));
|
|
4442
4797
|
console.log(`Created ${type} "${name}" at ${filePath}`);
|
|
4443
4798
|
console.log(`Edit it, then publish with: decantr publish ${type} ${name}`);
|
|
4444
4799
|
}
|
|
4445
4800
|
|
|
4446
4801
|
// src/commands/doctor.ts
|
|
4447
|
-
import { existsSync as
|
|
4448
|
-
import { dirname as dirname4, join as
|
|
4802
|
+
import { existsSync as existsSync17, readdirSync as readdirSync6, readFileSync as readFileSync14 } from "fs";
|
|
4803
|
+
import { dirname as dirname4, join as join19, relative as relative5 } from "path";
|
|
4449
4804
|
import { fileURLToPath } from "url";
|
|
4450
4805
|
import { isV4 as isV44 } from "@decantr/essence-spec";
|
|
4451
4806
|
import { collectMissingPackManifestFiles } from "@decantr/verifier";
|
|
@@ -4457,25 +4812,25 @@ var YELLOW3 = "\x1B[33m";
|
|
|
4457
4812
|
var CYAN2 = "\x1B[36m";
|
|
4458
4813
|
var RESET4 = "\x1B[0m";
|
|
4459
4814
|
function readJson2(path) {
|
|
4460
|
-
if (!
|
|
4815
|
+
if (!existsSync17(path)) return null;
|
|
4461
4816
|
try {
|
|
4462
|
-
return JSON.parse(
|
|
4817
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
4463
4818
|
} catch {
|
|
4464
4819
|
return null;
|
|
4465
4820
|
}
|
|
4466
4821
|
}
|
|
4467
4822
|
function isContractOnlyProject(projectRoot) {
|
|
4468
|
-
const projectJson = readJson2(
|
|
4469
|
-
return projectJson?.initialized?.adoptionMode === "contract-only";
|
|
4823
|
+
const projectJson = readJson2(join19(projectRoot, ".decantr", "project.json"));
|
|
4824
|
+
return projectJson?.initialized?.adoptionMode === "contract-only" || projectJson?.initialized?.adoptionMode === "style-bridge";
|
|
4470
4825
|
}
|
|
4471
4826
|
function readCliPackageVersion() {
|
|
4472
|
-
const packagePath =
|
|
4473
|
-
const srcPackagePath =
|
|
4827
|
+
const packagePath = join19(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
4828
|
+
const srcPackagePath = join19(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
4474
4829
|
const pkg = readJson2(packagePath) ?? readJson2(srcPackagePath);
|
|
4475
4830
|
return pkg?.version ?? "unknown";
|
|
4476
4831
|
}
|
|
4477
4832
|
function readPackageJson2(dir) {
|
|
4478
|
-
return readJson2(
|
|
4833
|
+
return readJson2(join19(dir, "package.json"));
|
|
4479
4834
|
}
|
|
4480
4835
|
function detectPackageManager3(root) {
|
|
4481
4836
|
const pkg = readPackageJson2(root);
|
|
@@ -4483,10 +4838,10 @@ function detectPackageManager3(root) {
|
|
|
4483
4838
|
if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
|
|
4484
4839
|
return declared;
|
|
4485
4840
|
}
|
|
4486
|
-
if (
|
|
4487
|
-
if (
|
|
4488
|
-
if (
|
|
4489
|
-
if (
|
|
4841
|
+
if (existsSync17(join19(root, "pnpm-lock.yaml"))) return "pnpm";
|
|
4842
|
+
if (existsSync17(join19(root, "package-lock.json"))) return "npm";
|
|
4843
|
+
if (existsSync17(join19(root, "yarn.lock"))) return "yarn";
|
|
4844
|
+
if (existsSync17(join19(root, "bun.lock")) || existsSync17(join19(root, "bun.lockb"))) return "bun";
|
|
4490
4845
|
return "unknown";
|
|
4491
4846
|
}
|
|
4492
4847
|
function localCliDependency(root) {
|
|
@@ -4496,7 +4851,7 @@ function localCliDependency(root) {
|
|
|
4496
4851
|
function hasWorkspaceMarker2(root) {
|
|
4497
4852
|
const pkg = readPackageJson2(root);
|
|
4498
4853
|
return Boolean(
|
|
4499
|
-
|
|
4854
|
+
existsSync17(join19(root, "pnpm-workspace.yaml")) || existsSync17(join19(root, "turbo.json")) || existsSync17(join19(root, "nx.json")) || pkg?.workspaces
|
|
4500
4855
|
);
|
|
4501
4856
|
}
|
|
4502
4857
|
function pinCliCommand2(packageManager, root) {
|
|
@@ -4519,8 +4874,8 @@ function rel(root, path) {
|
|
|
4519
4874
|
}
|
|
4520
4875
|
function hasAnyFile(dir, names) {
|
|
4521
4876
|
for (const name of names) {
|
|
4522
|
-
const path =
|
|
4523
|
-
if (
|
|
4877
|
+
const path = join19(dir, name);
|
|
4878
|
+
if (existsSync17(path)) return name;
|
|
4524
4879
|
}
|
|
4525
4880
|
return null;
|
|
4526
4881
|
}
|
|
@@ -4542,7 +4897,7 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
|
|
|
4542
4897
|
"libs/design-system"
|
|
4543
4898
|
];
|
|
4544
4899
|
for (const candidate of sharedCandidates) {
|
|
4545
|
-
if (
|
|
4900
|
+
if (existsSync17(join19(workspaceRoot, candidate))) found.add(candidate);
|
|
4546
4901
|
}
|
|
4547
4902
|
for (const root of [appRoot, workspaceRoot]) {
|
|
4548
4903
|
const label = root === appRoot ? "app" : "workspace";
|
|
@@ -4553,9 +4908,9 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
|
|
|
4553
4908
|
"tailwind.config.cjs"
|
|
4554
4909
|
]);
|
|
4555
4910
|
if (tailwind) found.add(`${label}:${tailwind}`);
|
|
4556
|
-
if (
|
|
4557
|
-
if (
|
|
4558
|
-
if (
|
|
4911
|
+
if (existsSync17(join19(root, ".storybook"))) found.add(`${label}:.storybook`);
|
|
4912
|
+
if (existsSync17(join19(root, "components", "ui"))) found.add(`${label}:components/ui`);
|
|
4913
|
+
if (existsSync17(join19(root, "src", "components", "ui"))) found.add(`${label}:src/components/ui`);
|
|
4559
4914
|
if (packageHasDependency(root, ["@storybook/react", "storybook"]))
|
|
4560
4915
|
found.add(`${label}:storybook`);
|
|
4561
4916
|
if (packageHasDependency(root, ["tailwindcss"])) found.add(`${label}:tailwindcss`);
|
|
@@ -4567,18 +4922,18 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
|
|
|
4567
4922
|
}
|
|
4568
4923
|
function findCiFiles(root) {
|
|
4569
4924
|
const files = [];
|
|
4570
|
-
const workflows =
|
|
4571
|
-
if (
|
|
4925
|
+
const workflows = join19(root, ".github", "workflows");
|
|
4926
|
+
if (existsSync17(workflows)) {
|
|
4572
4927
|
for (const entry of readdirSync6(workflows, { withFileTypes: true })) {
|
|
4573
4928
|
if (!entry.isFile()) continue;
|
|
4574
|
-
const path =
|
|
4575
|
-
const text =
|
|
4929
|
+
const path = join19(workflows, entry.name);
|
|
4930
|
+
const text = readFileSync14(path, "utf-8");
|
|
4576
4931
|
if (text.includes("decantr")) files.push(rel(root, path));
|
|
4577
4932
|
}
|
|
4578
4933
|
}
|
|
4579
4934
|
for (const candidate of ["Jenkinsfile", ".gitlab-ci.yml", "azure-pipelines.yml", "BUILD"]) {
|
|
4580
|
-
const path =
|
|
4581
|
-
if (
|
|
4935
|
+
const path = join19(root, candidate);
|
|
4936
|
+
if (existsSync17(path) && readFileSync14(path, "utf-8").includes("decantr")) {
|
|
4582
4937
|
files.push(candidate);
|
|
4583
4938
|
}
|
|
4584
4939
|
}
|
|
@@ -4618,15 +4973,17 @@ function deriveAdoptionLane(input) {
|
|
|
4618
4973
|
};
|
|
4619
4974
|
}
|
|
4620
4975
|
const hasLocalLaw = input.localPatternsPresent || input.localRulesPresent;
|
|
4976
|
+
const hasStyleBridge = input.styleBridgePresent || input.adoptionMode === "style-bridge";
|
|
4621
4977
|
if (input.workflowMode === "hybrid-compose") {
|
|
4622
4978
|
return {
|
|
4623
4979
|
id: "hybrid-compose",
|
|
4624
4980
|
label: "Hybrid composition",
|
|
4625
4981
|
sourceAuthority: "Existing app plus selected Decantr/local law",
|
|
4626
|
-
styleAuthority: input.adoptionMode === "decantr-css" ? "Decantr CSS runtime is active where adopted" :
|
|
4982
|
+
styleAuthority: input.adoptionMode === "decantr-css" ? "Decantr CSS runtime is active where adopted" : hasStyleBridge ? "Style bridge maps Decantr intent into the app styling system" : "Existing app styling system remains primary",
|
|
4627
4983
|
activeAuthorities: [
|
|
4628
4984
|
"existing source",
|
|
4629
4985
|
"Essence V4 contract",
|
|
4986
|
+
hasStyleBridge ? "accepted style bridge" : "no style bridge",
|
|
4630
4987
|
hasLocalLaw ? "accepted local law" : "reviewed Hybrid choices",
|
|
4631
4988
|
input.packManifestPresent ? "hosted execution packs" : "optional hosted packs"
|
|
4632
4989
|
],
|
|
@@ -4644,13 +5001,18 @@ function deriveAdoptionLane(input) {
|
|
|
4644
5001
|
nextChoice: "Keep Decantr CSS usage explicit and validate route changes with task and verify."
|
|
4645
5002
|
};
|
|
4646
5003
|
}
|
|
4647
|
-
if (
|
|
5004
|
+
if (hasStyleBridge) {
|
|
4648
5005
|
return {
|
|
4649
5006
|
id: "hybrid-style-bridge",
|
|
4650
5007
|
label: "Hybrid style bridge",
|
|
4651
5008
|
sourceAuthority: "Existing app plus Decantr intent mapped through a style bridge",
|
|
4652
5009
|
styleAuthority: "Style bridge over the existing app styling system",
|
|
4653
|
-
activeAuthorities: [
|
|
5010
|
+
activeAuthorities: [
|
|
5011
|
+
"existing source",
|
|
5012
|
+
"Essence V4 contract",
|
|
5013
|
+
"accepted style bridge",
|
|
5014
|
+
hasLocalLaw ? "accepted local patterns/rules" : "optional local law"
|
|
5015
|
+
],
|
|
4654
5016
|
nextChoice: "Use local law to decide which component families the bridge governs before making it strict."
|
|
4655
5017
|
};
|
|
4656
5018
|
}
|
|
@@ -4708,18 +5070,18 @@ function buildDoctorReport(root, args) {
|
|
|
4708
5070
|
const workspaceInfo = resolveWorkspaceInfo(root, projectArg);
|
|
4709
5071
|
const workspaceRoot = workspaceInfo.workspaceRoot;
|
|
4710
5072
|
const appRoot = workspaceMode ? workspaceRoot : workspaceInfo.appRoot;
|
|
4711
|
-
const projectMissing = Boolean(projectArg && !
|
|
5073
|
+
const projectMissing = Boolean(projectArg && !existsSync17(appRoot));
|
|
4712
5074
|
const projectPath = appRoot === workspaceRoot ? null : rel(workspaceRoot, appRoot);
|
|
4713
5075
|
const packageManager = detectPackageManager3(workspaceRoot);
|
|
4714
5076
|
const cliDependency = localCliDependency(workspaceRoot);
|
|
4715
5077
|
const detected = detectProject(appRoot);
|
|
4716
|
-
const projectJson = readJson2(
|
|
4717
|
-
const essence = readJson2(
|
|
5078
|
+
const projectJson = readJson2(join19(appRoot, ".decantr", "project.json"));
|
|
5079
|
+
const essence = readJson2(join19(appRoot, "decantr.essence.json"));
|
|
4718
5080
|
const essenceVersion = essence && typeof essence === "object" && "version" in essence ? String(essence.version) : null;
|
|
4719
|
-
const contextDir =
|
|
4720
|
-
const packManifestPresent =
|
|
4721
|
-
const reviewPackPresent =
|
|
4722
|
-
const artifactReadmePresent =
|
|
5081
|
+
const contextDir = join19(appRoot, ".decantr", "context");
|
|
5082
|
+
const packManifestPresent = existsSync17(join19(contextDir, "pack-manifest.json"));
|
|
5083
|
+
const reviewPackPresent = existsSync17(join19(contextDir, "review-pack.json"));
|
|
5084
|
+
const artifactReadmePresent = existsSync17(join19(appRoot, ARTIFACT_README_PATH));
|
|
4723
5085
|
const projects = listWorkspaceProjects(workspaceRoot);
|
|
4724
5086
|
const candidates = listWorkspaceCandidates(workspaceRoot, projects).map((candidate) => ({
|
|
4725
5087
|
path: candidate.path,
|
|
@@ -4729,21 +5091,23 @@ function buildDoctorReport(root, args) {
|
|
|
4729
5091
|
const ciFiles = findCiFiles(workspaceRoot);
|
|
4730
5092
|
const workflowMode = projectJson?.initialized?.workflowMode ?? null;
|
|
4731
5093
|
const adoptionMode = projectJson?.initialized?.adoptionMode ?? null;
|
|
4732
|
-
const packHydrationOptional = adoptionMode === "contract-only";
|
|
4733
|
-
const localPatternsPresent =
|
|
4734
|
-
const localRulesPresent =
|
|
5094
|
+
const packHydrationOptional = adoptionMode === "contract-only" || adoptionMode === "style-bridge";
|
|
5095
|
+
const localPatternsPresent = existsSync17(localPatternsPath(appRoot));
|
|
5096
|
+
const localRulesPresent = existsSync17(localRulesPath(appRoot));
|
|
5097
|
+
const styleBridgePresent = existsSync17(styleBridgePath(appRoot));
|
|
5098
|
+
const styleBridgeProposalPresent = existsSync17(styleBridgeProposalPath(appRoot));
|
|
4735
5099
|
const missingPackReferences = workspaceMode ? projects.flatMap(
|
|
4736
|
-
(project) => collectMissingPackManifestFiles(
|
|
5100
|
+
(project) => collectMissingPackManifestFiles(join19(workspaceRoot, project.path)).map(
|
|
4737
5101
|
(missing) => `${project.path}/${missing.relativePath}`
|
|
4738
5102
|
)
|
|
4739
5103
|
) : collectMissingPackManifestFiles(appRoot).map((missing) => missing.relativePath);
|
|
4740
5104
|
const workspaceProjectsMissingManifest = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
|
|
4741
|
-
const projectContextDir =
|
|
4742
|
-
return !isContractOnlyProject(
|
|
5105
|
+
const projectContextDir = join19(workspaceRoot, projectPath2, ".decantr", "context");
|
|
5106
|
+
return !isContractOnlyProject(join19(workspaceRoot, projectPath2)) && !existsSync17(join19(projectContextDir, "pack-manifest.json"));
|
|
4743
5107
|
}) : [];
|
|
4744
5108
|
const workspaceProjectsMissingReviewPack = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
|
|
4745
|
-
const projectContextDir =
|
|
4746
|
-
return !isContractOnlyProject(
|
|
5109
|
+
const projectContextDir = join19(workspaceRoot, projectPath2, ".decantr", "context");
|
|
5110
|
+
return !isContractOnlyProject(join19(workspaceRoot, projectPath2)) && !existsSync17(join19(projectContextDir, "review-pack.json"));
|
|
4747
5111
|
}) : [];
|
|
4748
5112
|
const issues = [];
|
|
4749
5113
|
if (projectMissing) {
|
|
@@ -4800,7 +5164,7 @@ function buildDoctorReport(root, args) {
|
|
|
4800
5164
|
nextCommand: "decantr refresh"
|
|
4801
5165
|
});
|
|
4802
5166
|
}
|
|
4803
|
-
if (essenceVersion === "4.0.0" && !packHydrationOptional && (!
|
|
5167
|
+
if (essenceVersion === "4.0.0" && !packHydrationOptional && (!existsSync17(contextDir) || !packManifestPresent)) {
|
|
4804
5168
|
issues.push({
|
|
4805
5169
|
category: "generated-artifact",
|
|
4806
5170
|
severity: "warn",
|
|
@@ -4832,6 +5196,14 @@ function buildDoctorReport(root, args) {
|
|
|
4832
5196
|
nextCommand: projectPath ? `decantr codify --from-audit --project ${projectPath}` : "decantr codify --from-audit"
|
|
4833
5197
|
});
|
|
4834
5198
|
}
|
|
5199
|
+
if (adoptionMode === "style-bridge" && !styleBridgePresent) {
|
|
5200
|
+
issues.push({
|
|
5201
|
+
category: "local-law",
|
|
5202
|
+
severity: "warn",
|
|
5203
|
+
message: "This app declares style-bridge adoption, but .decantr/style-bridge.json is missing.",
|
|
5204
|
+
nextCommand: styleBridgeProposalPresent ? projectPath ? `decantr codify --accept --project ${projectPath}` : "decantr codify --accept" : projectPath ? `decantr codify --style-bridge --project ${projectPath}` : "decantr codify --style-bridge"
|
|
5205
|
+
});
|
|
5206
|
+
}
|
|
4835
5207
|
if ((essenceVersion === "4.0.0" || workspaceMode && projects.length > 0) && ciFiles.length === 0) {
|
|
4836
5208
|
issues.push({
|
|
4837
5209
|
category: "ci",
|
|
@@ -4859,6 +5231,7 @@ function buildDoctorReport(root, args) {
|
|
|
4859
5231
|
adoptionMode,
|
|
4860
5232
|
localPatternsPresent,
|
|
4861
5233
|
localRulesPresent,
|
|
5234
|
+
styleBridgePresent,
|
|
4862
5235
|
designAuthority,
|
|
4863
5236
|
packManifestPresent
|
|
4864
5237
|
});
|
|
@@ -4880,6 +5253,12 @@ function buildDoctorReport(root, args) {
|
|
|
4880
5253
|
appendUnique(recommendedNextCommands, `decantr codify --from-audit${projectFlag}`);
|
|
4881
5254
|
appendUnique(recommendedNextCommands, `decantr codify --accept${projectFlag}`);
|
|
4882
5255
|
}
|
|
5256
|
+
if (adoptionMode === "style-bridge" && !styleBridgePresent) {
|
|
5257
|
+
appendUnique(
|
|
5258
|
+
recommendedNextCommands,
|
|
5259
|
+
styleBridgeProposalPresent ? `decantr codify --accept${projectFlag}` : `decantr codify --style-bridge${projectFlag}`
|
|
5260
|
+
);
|
|
5261
|
+
}
|
|
4883
5262
|
appendUnique(
|
|
4884
5263
|
recommendedNextCommands,
|
|
4885
5264
|
issues.find((issue) => issue.category === "generated-artifact")?.nextCommand
|
|
@@ -4919,18 +5298,20 @@ function buildDoctorReport(root, args) {
|
|
|
4919
5298
|
},
|
|
4920
5299
|
generatedArtifacts: {
|
|
4921
5300
|
contextDirPresent: workspaceMode ? projects.some(
|
|
4922
|
-
(project) =>
|
|
4923
|
-
) :
|
|
5301
|
+
(project) => existsSync17(join19(workspaceRoot, project.path, ".decantr", "context"))
|
|
5302
|
+
) : existsSync17(contextDir),
|
|
4924
5303
|
packManifestPresent: workspaceMode ? projects.length > 0 && workspaceProjectsMissingManifest.length === 0 : packManifestPresent,
|
|
4925
5304
|
reviewPackPresent: workspaceMode ? projects.length > 0 && workspaceProjectsMissingReviewPack.length === 0 : reviewPackPresent,
|
|
4926
5305
|
missingReferencedFiles: missingPackReferences.slice(0, 25)
|
|
4927
5306
|
},
|
|
4928
5307
|
localLaw: {
|
|
4929
5308
|
patternsPresent: localPatternsPresent,
|
|
4930
|
-
rulesPresent: localRulesPresent
|
|
5309
|
+
rulesPresent: localRulesPresent,
|
|
5310
|
+
styleBridgePresent,
|
|
5311
|
+
styleBridgeProposalPresent
|
|
4931
5312
|
},
|
|
4932
5313
|
visualEvidence: {
|
|
4933
|
-
manifestPresent:
|
|
5314
|
+
manifestPresent: existsSync17(join19(appRoot, ".decantr", "evidence", "visual-manifest.json"))
|
|
4934
5315
|
},
|
|
4935
5316
|
lane,
|
|
4936
5317
|
designAuthority,
|
|
@@ -4978,6 +5359,7 @@ function formatDoctorText(report) {
|
|
|
4978
5359
|
`${BOLD3}Local Law:${RESET4}`,
|
|
4979
5360
|
` Local patterns: ${report.localLaw.patternsPresent ? "present" : "missing"}`,
|
|
4980
5361
|
` Local rules: ${report.localLaw.rulesPresent ? "present" : "missing"}`,
|
|
5362
|
+
` Style bridge: ${report.localLaw.styleBridgePresent ? "present" : report.localLaw.styleBridgeProposalPresent ? "proposal pending" : "missing"}`,
|
|
4981
5363
|
"",
|
|
4982
5364
|
`${BOLD3}Workspace:${RESET4}`,
|
|
4983
5365
|
` Attached projects: ${report.workspace.attachedProjects.length}`,
|
|
@@ -5037,17 +5419,17 @@ async function cmdDoctor(args = ["doctor"], root = process.cwd()) {
|
|
|
5037
5419
|
}
|
|
5038
5420
|
|
|
5039
5421
|
// src/commands/export.ts
|
|
5040
|
-
import { existsSync as
|
|
5041
|
-
import { dirname as dirname5, isAbsolute, join as
|
|
5422
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "fs";
|
|
5423
|
+
import { dirname as dirname5, isAbsolute, join as join20 } from "path";
|
|
5042
5424
|
var GREEN5 = "\x1B[32m";
|
|
5043
5425
|
var RED4 = "\x1B[31m";
|
|
5044
5426
|
var DIM5 = "\x1B[2m";
|
|
5045
5427
|
var RESET5 = "\x1B[0m";
|
|
5046
5428
|
function readAdoptionMode(projectRoot) {
|
|
5047
|
-
const projectJsonPath =
|
|
5048
|
-
if (!
|
|
5429
|
+
const projectJsonPath = join20(projectRoot, ".decantr", "project.json");
|
|
5430
|
+
if (!existsSync18(projectJsonPath)) return null;
|
|
5049
5431
|
try {
|
|
5050
|
-
const parsed = JSON.parse(
|
|
5432
|
+
const parsed = JSON.parse(readFileSync15(projectJsonPath, "utf-8"));
|
|
5051
5433
|
return typeof parsed.initialized?.adoptionMode === "string" ? parsed.initialized.adoptionMode : null;
|
|
5052
5434
|
} catch {
|
|
5053
5435
|
return null;
|
|
@@ -5055,7 +5437,7 @@ function readAdoptionMode(projectRoot) {
|
|
|
5055
5437
|
}
|
|
5056
5438
|
function resolveOutputPath(projectRoot, output, fallback) {
|
|
5057
5439
|
if (!output) return fallback;
|
|
5058
|
-
return isAbsolute(output) ? output :
|
|
5440
|
+
return isAbsolute(output) ? output : join20(projectRoot, output);
|
|
5059
5441
|
}
|
|
5060
5442
|
var SHADCN_MAP = {
|
|
5061
5443
|
"--d-bg": "--background",
|
|
@@ -5216,21 +5598,21 @@ function generateFigmaTokens(tokens) {
|
|
|
5216
5598
|
`;
|
|
5217
5599
|
}
|
|
5218
5600
|
async function cmdExport(target, projectRoot, options = {}) {
|
|
5219
|
-
const essencePath =
|
|
5220
|
-
const tokensPath =
|
|
5221
|
-
if (!
|
|
5601
|
+
const essencePath = join20(projectRoot, "decantr.essence.json");
|
|
5602
|
+
const tokensPath = join20(projectRoot, "src", "styles", "tokens.css");
|
|
5603
|
+
if (!existsSync18(essencePath)) {
|
|
5222
5604
|
console.error(`${RED4}No decantr.essence.json found. Run \`decantr init\` first.${RESET5}`);
|
|
5223
5605
|
process.exitCode = 1;
|
|
5224
5606
|
return;
|
|
5225
5607
|
}
|
|
5226
|
-
if (!
|
|
5608
|
+
if (!existsSync18(tokensPath)) {
|
|
5227
5609
|
const adoptionMode = readAdoptionMode(projectRoot);
|
|
5228
5610
|
const message = adoptionMode === "contract-only" ? `No src/styles/tokens.css found. This export reads Decantr CSS tokens, but this project is contract-only Brownfield and may intentionally use its own Tailwind/Sass token system. Export from the app's token source or adopt a style bridge before using \`decantr export --to ${target}\`.` : "No src/styles/tokens.css found. Run `decantr refresh` to generate tokens.";
|
|
5229
5611
|
console.error(`${RED4}${message}${RESET5}`);
|
|
5230
5612
|
process.exitCode = 1;
|
|
5231
5613
|
return;
|
|
5232
5614
|
}
|
|
5233
|
-
const tokensCSS =
|
|
5615
|
+
const tokensCSS = readFileSync15(tokensPath, "utf-8");
|
|
5234
5616
|
const tokens = parseTokensCSS(tokensCSS);
|
|
5235
5617
|
if (tokens.size === 0) {
|
|
5236
5618
|
console.error(`${RED4}No --d-* tokens found in tokens.css.${RESET5}`);
|
|
@@ -5242,12 +5624,12 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
5242
5624
|
const cssOut = resolveOutputPath(
|
|
5243
5625
|
projectRoot,
|
|
5244
5626
|
options.output,
|
|
5245
|
-
|
|
5627
|
+
join20(projectRoot, "src", "styles", "shadcn-theme.css")
|
|
5246
5628
|
);
|
|
5247
|
-
const jsonOut =
|
|
5629
|
+
const jsonOut = join20(projectRoot, "components.json");
|
|
5248
5630
|
ensureDir(cssOut);
|
|
5249
|
-
|
|
5250
|
-
|
|
5631
|
+
writeFileSync13(cssOut, generateShadcnCSS(tokens), "utf-8");
|
|
5632
|
+
writeFileSync13(jsonOut, generateShadcnComponentsJSON(), "utf-8");
|
|
5251
5633
|
console.log(`${GREEN5}Exported shadcn theme:${RESET5}`);
|
|
5252
5634
|
console.log(` ${DIM5}CSS:${RESET5} ${cssOut}`);
|
|
5253
5635
|
console.log(` ${DIM5}JSON:${RESET5} ${jsonOut}`);
|
|
@@ -5257,10 +5639,10 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
5257
5639
|
const out = resolveOutputPath(
|
|
5258
5640
|
projectRoot,
|
|
5259
5641
|
options.output,
|
|
5260
|
-
|
|
5642
|
+
join20(projectRoot, "tailwind.decantr.config.ts")
|
|
5261
5643
|
);
|
|
5262
5644
|
ensureDir(out);
|
|
5263
|
-
|
|
5645
|
+
writeFileSync13(out, generateTailwindConfig(tokens), "utf-8");
|
|
5264
5646
|
console.log(`${GREEN5}Exported Tailwind config:${RESET5}`);
|
|
5265
5647
|
console.log(` ${DIM5}File:${RESET5} ${out}`);
|
|
5266
5648
|
break;
|
|
@@ -5269,10 +5651,10 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
5269
5651
|
const out = resolveOutputPath(
|
|
5270
5652
|
projectRoot,
|
|
5271
5653
|
options.output,
|
|
5272
|
-
|
|
5654
|
+
join20(projectRoot, "decantr-tokens.css")
|
|
5273
5655
|
);
|
|
5274
5656
|
ensureDir(out);
|
|
5275
|
-
|
|
5657
|
+
writeFileSync13(out, generateCSSVars(tokens), "utf-8");
|
|
5276
5658
|
console.log(`${GREEN5}Exported CSS variables:${RESET5}`);
|
|
5277
5659
|
console.log(` ${DIM5}File:${RESET5} ${out}`);
|
|
5278
5660
|
break;
|
|
@@ -5281,10 +5663,10 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
5281
5663
|
const out = resolveOutputPath(
|
|
5282
5664
|
projectRoot,
|
|
5283
5665
|
options.output,
|
|
5284
|
-
|
|
5666
|
+
join20(projectRoot, ".decantr", "design", "figma-tokens.json")
|
|
5285
5667
|
);
|
|
5286
5668
|
ensureDir(out);
|
|
5287
|
-
|
|
5669
|
+
writeFileSync13(out, generateFigmaTokens(tokens), "utf-8");
|
|
5288
5670
|
console.log(`${GREEN5}Exported Figma/Tokens Studio tokens:${RESET5}`);
|
|
5289
5671
|
console.log(` ${DIM5}File:${RESET5} ${out}`);
|
|
5290
5672
|
break;
|
|
@@ -5293,15 +5675,15 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
5293
5675
|
}
|
|
5294
5676
|
function ensureDir(filePath) {
|
|
5295
5677
|
const dir = dirname5(filePath);
|
|
5296
|
-
if (!
|
|
5297
|
-
|
|
5678
|
+
if (!existsSync18(dir)) {
|
|
5679
|
+
mkdirSync12(dir, { recursive: true });
|
|
5298
5680
|
}
|
|
5299
5681
|
}
|
|
5300
5682
|
|
|
5301
5683
|
// src/commands/magic.ts
|
|
5302
|
-
import { existsSync as
|
|
5684
|
+
import { existsSync as existsSync19 } from "fs";
|
|
5303
5685
|
import * as fs from "fs/promises";
|
|
5304
|
-
import { join as
|
|
5686
|
+
import { join as join21 } from "path";
|
|
5305
5687
|
var BOLD4 = "\x1B[1m";
|
|
5306
5688
|
var DIM6 = "\x1B[2m";
|
|
5307
5689
|
var RESET6 = "\x1B[0m";
|
|
@@ -5525,8 +5907,8 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
5525
5907
|
console.log(` Archetype: ${intent.archetype}`);
|
|
5526
5908
|
}
|
|
5527
5909
|
console.log("");
|
|
5528
|
-
const essencePath =
|
|
5529
|
-
if (
|
|
5910
|
+
const essencePath = join21(projectRoot, "decantr.essence.json");
|
|
5911
|
+
if (existsSync19(essencePath)) {
|
|
5530
5912
|
const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
|
|
5531
5913
|
console.log(`${YELLOW4} Decantr is already attached to this project.${RESET6}`);
|
|
5532
5914
|
console.log(
|
|
@@ -5559,7 +5941,7 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
5559
5941
|
return;
|
|
5560
5942
|
}
|
|
5561
5943
|
const registryClient = new RegistryClient({
|
|
5562
|
-
cacheDir:
|
|
5944
|
+
cacheDir: join21(projectRoot, ".decantr", "cache"),
|
|
5563
5945
|
apiUrl: options.registry,
|
|
5564
5946
|
offline: options.offline
|
|
5565
5947
|
});
|
|
@@ -5830,14 +6212,14 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
5830
6212
|
if (result.gitignoreUpdated) {
|
|
5831
6213
|
console.log(` ${dim(".gitignore updated")}`);
|
|
5832
6214
|
}
|
|
5833
|
-
const contextDir =
|
|
6215
|
+
const contextDir = join21(projectRoot, ".decantr", "context");
|
|
5834
6216
|
let sectionCount = 0;
|
|
5835
6217
|
try {
|
|
5836
6218
|
const files = await fs.readdir(contextDir);
|
|
5837
6219
|
sectionCount = files.filter((f) => f.startsWith("section-")).length;
|
|
5838
6220
|
} catch {
|
|
5839
6221
|
}
|
|
5840
|
-
const treatmentsPath =
|
|
6222
|
+
const treatmentsPath = join21(projectRoot, "src", "styles", "treatments.css");
|
|
5841
6223
|
let hasLayers = false;
|
|
5842
6224
|
try {
|
|
5843
6225
|
const css = await fs.readFile(treatmentsPath, "utf-8");
|
|
@@ -5870,8 +6252,8 @@ ${GREEN6}${BOLD4}Quality summary:${RESET6}`);
|
|
|
5870
6252
|
}
|
|
5871
6253
|
|
|
5872
6254
|
// src/commands/migrate.ts
|
|
5873
|
-
import { copyFileSync, existsSync as
|
|
5874
|
-
import { join as
|
|
6255
|
+
import { copyFileSync, existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
6256
|
+
import { join as join22 } from "path";
|
|
5875
6257
|
import {
|
|
5876
6258
|
isV4 as isV45,
|
|
5877
6259
|
migrateToV4,
|
|
@@ -5884,12 +6266,12 @@ var YELLOW5 = "\x1B[33m";
|
|
|
5884
6266
|
var RESET7 = "\x1B[0m";
|
|
5885
6267
|
var DIM7 = "\x1B[2m";
|
|
5886
6268
|
function migrateEssenceFile(essencePath) {
|
|
5887
|
-
if (!
|
|
6269
|
+
if (!existsSync20(essencePath)) {
|
|
5888
6270
|
return { success: false, error: `File not found: ${essencePath}` };
|
|
5889
6271
|
}
|
|
5890
6272
|
let raw;
|
|
5891
6273
|
try {
|
|
5892
|
-
raw =
|
|
6274
|
+
raw = readFileSync16(essencePath, "utf-8");
|
|
5893
6275
|
} catch (e) {
|
|
5894
6276
|
return { success: false, error: `Could not read ${essencePath}: ${e.message}` };
|
|
5895
6277
|
}
|
|
@@ -5930,7 +6312,7 @@ function migrateEssenceFile(essencePath) {
|
|
|
5930
6312
|
};
|
|
5931
6313
|
}
|
|
5932
6314
|
try {
|
|
5933
|
-
|
|
6315
|
+
writeFileSync14(essencePath, JSON.stringify(v4, null, 2) + "\n");
|
|
5934
6316
|
} catch (e) {
|
|
5935
6317
|
return {
|
|
5936
6318
|
success: false,
|
|
@@ -5951,8 +6333,8 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
|
|
|
5951
6333
|
process.exitCode = 1;
|
|
5952
6334
|
return;
|
|
5953
6335
|
}
|
|
5954
|
-
const essencePath =
|
|
5955
|
-
if (!
|
|
6336
|
+
const essencePath = join22(projectRoot, "decantr.essence.json");
|
|
6337
|
+
if (!existsSync20(essencePath)) {
|
|
5956
6338
|
console.error(`${RED5}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
|
|
5957
6339
|
process.exitCode = 1;
|
|
5958
6340
|
return;
|
|
@@ -5974,7 +6356,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
|
|
|
5974
6356
|
}
|
|
5975
6357
|
if (result.essence) {
|
|
5976
6358
|
const registryClient = new RegistryClient({
|
|
5977
|
-
cacheDir:
|
|
6359
|
+
cacheDir: join22(projectRoot, ".decantr", "cache")
|
|
5978
6360
|
});
|
|
5979
6361
|
await refreshDerivedFiles(projectRoot, result.essence, registryClient);
|
|
5980
6362
|
console.log(`${GREEN7}Derived context and execution packs refreshed.${RESET7}`);
|
|
@@ -5985,50 +6367,50 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
|
|
|
5985
6367
|
|
|
5986
6368
|
// src/commands/new-project.ts
|
|
5987
6369
|
import { spawnSync } from "child_process";
|
|
5988
|
-
import { existsSync as
|
|
5989
|
-
import { join as
|
|
6370
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync14 } from "fs";
|
|
6371
|
+
import { join as join24, resolve as resolve3 } from "path";
|
|
5990
6372
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5991
6373
|
|
|
5992
6374
|
// src/offline-content.ts
|
|
5993
|
-
import { cpSync, existsSync as
|
|
5994
|
-
import { join as
|
|
6375
|
+
import { cpSync, existsSync as existsSync21, mkdirSync as mkdirSync13 } from "fs";
|
|
6376
|
+
import { join as join23, resolve as resolve2 } from "path";
|
|
5995
6377
|
var CONTENT_TYPES2 = ["archetypes", "blueprints", "patterns", "themes", "shells"];
|
|
5996
6378
|
function copyIfExists(source, target) {
|
|
5997
|
-
if (!
|
|
6379
|
+
if (!existsSync21(source)) return false;
|
|
5998
6380
|
if (resolve2(source) === resolve2(target)) return true;
|
|
5999
6381
|
cpSync(source, target, { recursive: true });
|
|
6000
6382
|
return true;
|
|
6001
6383
|
}
|
|
6002
6384
|
function hydrateContentRoot(projectDir, contentRoot) {
|
|
6003
|
-
if (!
|
|
6004
|
-
const customRoot =
|
|
6005
|
-
const cacheRoot =
|
|
6006
|
-
|
|
6007
|
-
|
|
6385
|
+
if (!existsSync21(contentRoot)) return false;
|
|
6386
|
+
const customRoot = join23(projectDir, ".decantr", "custom");
|
|
6387
|
+
const cacheRoot = join23(projectDir, ".decantr", "cache", "@official");
|
|
6388
|
+
mkdirSync13(customRoot, { recursive: true });
|
|
6389
|
+
mkdirSync13(cacheRoot, { recursive: true });
|
|
6008
6390
|
let copiedAny = false;
|
|
6009
6391
|
for (const type of CONTENT_TYPES2) {
|
|
6010
|
-
const sourceDir =
|
|
6011
|
-
if (!
|
|
6012
|
-
cpSync(sourceDir,
|
|
6013
|
-
cpSync(sourceDir,
|
|
6392
|
+
const sourceDir = join23(contentRoot, type);
|
|
6393
|
+
if (!existsSync21(sourceDir)) continue;
|
|
6394
|
+
cpSync(sourceDir, join23(customRoot, type), { recursive: true });
|
|
6395
|
+
cpSync(sourceDir, join23(cacheRoot, type), { recursive: true });
|
|
6014
6396
|
copiedAny = true;
|
|
6015
6397
|
}
|
|
6016
6398
|
return copiedAny;
|
|
6017
6399
|
}
|
|
6018
6400
|
function seedOfflineRegistry(projectDir, workspaceRoot) {
|
|
6019
|
-
const projectDecantrRoot =
|
|
6020
|
-
|
|
6401
|
+
const projectDecantrRoot = join23(projectDir, ".decantr");
|
|
6402
|
+
mkdirSync13(projectDecantrRoot, { recursive: true });
|
|
6021
6403
|
const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve2(process.env.DECANTR_CONTENT_DIR) : null;
|
|
6022
6404
|
if (configuredContentRoot && hydrateContentRoot(projectDir, configuredContentRoot)) {
|
|
6023
6405
|
return { seeded: true, strategy: "configured-content-root" };
|
|
6024
6406
|
}
|
|
6025
6407
|
const copiedCache = copyIfExists(
|
|
6026
|
-
|
|
6027
|
-
|
|
6408
|
+
join23(workspaceRoot, ".decantr", "cache"),
|
|
6409
|
+
join23(projectDecantrRoot, "cache")
|
|
6028
6410
|
);
|
|
6029
6411
|
const copiedCustom = copyIfExists(
|
|
6030
|
-
|
|
6031
|
-
|
|
6412
|
+
join23(workspaceRoot, ".decantr", "custom"),
|
|
6413
|
+
join23(projectDecantrRoot, "custom")
|
|
6032
6414
|
);
|
|
6033
6415
|
if (copiedCache || copiedCustom) {
|
|
6034
6416
|
return { seeded: true, strategy: "workspace-cache" };
|
|
@@ -6141,7 +6523,7 @@ function runArgvCommand(command, args, cwd) {
|
|
|
6141
6523
|
}
|
|
6142
6524
|
function resolveInitCommand(initFlags) {
|
|
6143
6525
|
const bundledCliEntrypoint = fileURLToPath2(new URL("./bin.js", import.meta.url));
|
|
6144
|
-
const cliEntrypoint =
|
|
6526
|
+
const cliEntrypoint = existsSync22(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync22(process.argv[1]) ? process.argv[1] : null;
|
|
6145
6527
|
if (cliEntrypoint) {
|
|
6146
6528
|
return {
|
|
6147
6529
|
command: process.execPath,
|
|
@@ -6169,7 +6551,7 @@ async function cmdNewProject(projectName, options) {
|
|
|
6169
6551
|
process.exitCode = 1;
|
|
6170
6552
|
return;
|
|
6171
6553
|
}
|
|
6172
|
-
if (
|
|
6554
|
+
if (existsSync22(projectDir)) {
|
|
6173
6555
|
console.error(error(`Directory "${projectName}" already exists.`));
|
|
6174
6556
|
process.exitCode = 1;
|
|
6175
6557
|
return;
|
|
@@ -6183,7 +6565,7 @@ async function cmdNewProject(projectName, options) {
|
|
|
6183
6565
|
return;
|
|
6184
6566
|
}
|
|
6185
6567
|
console.log(heading(`Creating ${projectName}...`));
|
|
6186
|
-
|
|
6568
|
+
mkdirSync14(projectDir, { recursive: true });
|
|
6187
6569
|
console.log(dim2(` Created ${projectName}/`));
|
|
6188
6570
|
const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
6189
6571
|
if (shouldBootstrapRuntime && bootstrapAdapter) {
|
|
@@ -6282,21 +6664,21 @@ ${YELLOW6}Decantr init encountered issues. Run \`decantr init\` manually inside
|
|
|
6282
6664
|
}
|
|
6283
6665
|
}
|
|
6284
6666
|
function detectPackageManager4() {
|
|
6285
|
-
if (
|
|
6667
|
+
if (existsSync22(join24(process.cwd(), "pnpm-lock.yaml")) || existsSync22(join24(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
6286
6668
|
return "pnpm";
|
|
6287
6669
|
}
|
|
6288
|
-
if (
|
|
6670
|
+
if (existsSync22(join24(process.cwd(), "yarn.lock"))) {
|
|
6289
6671
|
return "yarn";
|
|
6290
6672
|
}
|
|
6291
|
-
if (
|
|
6673
|
+
if (existsSync22(join24(process.cwd(), "bun.lockb")) || existsSync22(join24(process.cwd(), "bun.lock"))) {
|
|
6292
6674
|
return "bun";
|
|
6293
6675
|
}
|
|
6294
6676
|
return "npm";
|
|
6295
6677
|
}
|
|
6296
6678
|
|
|
6297
6679
|
// src/commands/publish.ts
|
|
6298
|
-
import { existsSync as
|
|
6299
|
-
import { join as
|
|
6680
|
+
import { existsSync as existsSync23, readFileSync as readFileSync17 } from "fs";
|
|
6681
|
+
import { join as join25 } from "path";
|
|
6300
6682
|
import {
|
|
6301
6683
|
API_CONTENT_TYPE_TO_CONTENT_TYPE,
|
|
6302
6684
|
CONTENT_TYPE_TO_API_CONTENT_TYPE as CONTENT_TYPE_TO_API_CONTENT_TYPE2,
|
|
@@ -6312,8 +6694,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
6312
6694
|
}
|
|
6313
6695
|
const singularType = API_CONTENT_TYPE_TO_CONTENT_TYPE[type] || type;
|
|
6314
6696
|
const pluralType = CONTENT_TYPE_TO_API_CONTENT_TYPE2[type] || CONTENT_TYPE_TO_API_CONTENT_TYPE2[singularType] || `${type}s`;
|
|
6315
|
-
const customPath =
|
|
6316
|
-
if (!
|
|
6697
|
+
const customPath = join25(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
|
|
6698
|
+
if (!existsSync23(customPath)) {
|
|
6317
6699
|
console.error(`Custom ${singularType} "${name}" not found at ${customPath}`);
|
|
6318
6700
|
console.error(`Create one first: decantr create ${singularType} ${name}`);
|
|
6319
6701
|
process.exitCode = 1;
|
|
@@ -6321,7 +6703,7 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
6321
6703
|
}
|
|
6322
6704
|
let data;
|
|
6323
6705
|
try {
|
|
6324
|
-
data = JSON.parse(
|
|
6706
|
+
data = JSON.parse(readFileSync17(customPath, "utf-8"));
|
|
6325
6707
|
} catch {
|
|
6326
6708
|
console.error(`Failed to parse ${customPath}`);
|
|
6327
6709
|
process.exitCode = 1;
|
|
@@ -6360,8 +6742,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
|
|
|
6360
6742
|
|
|
6361
6743
|
// src/commands/refresh.ts
|
|
6362
6744
|
import { createHash } from "crypto";
|
|
6363
|
-
import { existsSync as
|
|
6364
|
-
import { isAbsolute as isAbsolute2, join as
|
|
6745
|
+
import { existsSync as existsSync24, readdirSync as readdirSync7, readFileSync as readFileSync18, statSync as statSync6 } from "fs";
|
|
6746
|
+
import { isAbsolute as isAbsolute2, join as join26, relative as relative6 } from "path";
|
|
6365
6747
|
import { collectMissingPackManifestFiles as collectMissingPackManifestFiles2 } from "@decantr/verifier";
|
|
6366
6748
|
import { isV4 as isV46 } from "@decantr/essence-spec";
|
|
6367
6749
|
var GREEN9 = "\x1B[32m";
|
|
@@ -6369,13 +6751,13 @@ var RED7 = "\x1B[31m";
|
|
|
6369
6751
|
var DIM9 = "\x1B[2m";
|
|
6370
6752
|
var RESET9 = "\x1B[0m";
|
|
6371
6753
|
function hashFile(path) {
|
|
6372
|
-
return createHash("sha256").update(
|
|
6754
|
+
return createHash("sha256").update(readFileSync18(path)).digest("hex");
|
|
6373
6755
|
}
|
|
6374
6756
|
function walkFiles(dir) {
|
|
6375
|
-
if (!
|
|
6757
|
+
if (!existsSync24(dir)) return [];
|
|
6376
6758
|
const files = [];
|
|
6377
6759
|
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
6378
|
-
const path =
|
|
6760
|
+
const path = join26(dir, entry.name);
|
|
6379
6761
|
if (entry.isDirectory()) {
|
|
6380
6762
|
files.push(...walkFiles(path));
|
|
6381
6763
|
} else if (entry.isFile()) {
|
|
@@ -6386,10 +6768,10 @@ function walkFiles(dir) {
|
|
|
6386
6768
|
}
|
|
6387
6769
|
function trackedGeneratedFiles(projectRoot) {
|
|
6388
6770
|
return [
|
|
6389
|
-
|
|
6390
|
-
...walkFiles(
|
|
6391
|
-
...["global.css", "tokens.css", "treatments.css", "decantr-bridge.css"].map((file) =>
|
|
6392
|
-
].filter((path) =>
|
|
6771
|
+
join26(projectRoot, "DECANTR.md"),
|
|
6772
|
+
...walkFiles(join26(projectRoot, ".decantr", "context")),
|
|
6773
|
+
...["global.css", "tokens.css", "treatments.css", "decantr-bridge.css"].map((file) => join26(projectRoot, "src", "styles", file)).filter((path) => existsSync24(path))
|
|
6774
|
+
].filter((path) => existsSync24(path));
|
|
6393
6775
|
}
|
|
6394
6776
|
function snapshotGeneratedFiles(projectRoot) {
|
|
6395
6777
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -6412,33 +6794,33 @@ function fileMtimeMs(path) {
|
|
|
6412
6794
|
}
|
|
6413
6795
|
function newestInputMtime(projectRoot) {
|
|
6414
6796
|
return Math.max(
|
|
6415
|
-
fileMtimeMs(
|
|
6416
|
-
fileMtimeMs(
|
|
6797
|
+
fileMtimeMs(join26(projectRoot, "decantr.essence.json")),
|
|
6798
|
+
fileMtimeMs(join26(projectRoot, ".decantr", "project.json"))
|
|
6417
6799
|
);
|
|
6418
6800
|
}
|
|
6419
6801
|
function isContractOnlyProject2(projectRoot) {
|
|
6420
|
-
const projectJsonPath =
|
|
6421
|
-
if (!
|
|
6802
|
+
const projectJsonPath = join26(projectRoot, ".decantr", "project.json");
|
|
6803
|
+
if (!existsSync24(projectJsonPath)) return false;
|
|
6422
6804
|
try {
|
|
6423
|
-
const projectJson = JSON.parse(
|
|
6805
|
+
const projectJson = JSON.parse(readFileSync18(projectJsonPath, "utf-8"));
|
|
6424
6806
|
return projectJson.initialized?.adoptionMode === "contract-only";
|
|
6425
6807
|
} catch {
|
|
6426
6808
|
return false;
|
|
6427
6809
|
}
|
|
6428
6810
|
}
|
|
6429
6811
|
function checkRefreshFreshness(projectRoot) {
|
|
6430
|
-
const contextDir =
|
|
6812
|
+
const contextDir = join26(projectRoot, ".decantr", "context");
|
|
6431
6813
|
const generated = trackedGeneratedFiles(projectRoot);
|
|
6432
6814
|
const reasons = [];
|
|
6433
6815
|
const packHydrationOptional = isContractOnlyProject2(projectRoot);
|
|
6434
|
-
if (!
|
|
6435
|
-
if (!
|
|
6436
|
-
if (!
|
|
6816
|
+
if (!existsSync24(join26(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
|
|
6817
|
+
if (!existsSync24(contextDir)) reasons.push(".decantr/context is missing.");
|
|
6818
|
+
if (!existsSync24(join26(contextDir, "scaffold.md"))) {
|
|
6437
6819
|
reasons.push(".decantr/context/scaffold.md is missing.");
|
|
6438
6820
|
}
|
|
6439
|
-
if (!packHydrationOptional && !
|
|
6821
|
+
if (!packHydrationOptional && !existsSync24(join26(contextDir, "pack-manifest.json"))) {
|
|
6440
6822
|
reasons.push(".decantr/context/pack-manifest.json is missing.");
|
|
6441
|
-
} else if (
|
|
6823
|
+
} else if (existsSync24(join26(contextDir, "pack-manifest.json"))) {
|
|
6442
6824
|
const missingPackFiles = collectMissingPackManifestFiles2(projectRoot);
|
|
6443
6825
|
if (missingPackFiles.length > 0) {
|
|
6444
6826
|
reasons.push(
|
|
@@ -6491,7 +6873,7 @@ function summarizeChanges(projectRoot, before, after) {
|
|
|
6491
6873
|
}
|
|
6492
6874
|
function displayGeneratedPath(summary, file, displayRoot) {
|
|
6493
6875
|
if (!displayRoot) return file;
|
|
6494
|
-
const absolutePath =
|
|
6876
|
+
const absolutePath = join26(summary.projectRoot, file);
|
|
6495
6877
|
const relativePath = relative6(displayRoot, absolutePath).replace(/\\/g, "/");
|
|
6496
6878
|
if (relativePath && !relativePath.startsWith("..") && !isAbsolute2(relativePath)) {
|
|
6497
6879
|
return relativePath;
|
|
@@ -6526,15 +6908,15 @@ function printRefreshSummary(summary, displayRoot) {
|
|
|
6526
6908
|
}
|
|
6527
6909
|
}
|
|
6528
6910
|
async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
|
|
6529
|
-
const essencePath =
|
|
6530
|
-
if (!
|
|
6911
|
+
const essencePath = join26(projectRoot, "decantr.essence.json");
|
|
6912
|
+
if (!existsSync24(essencePath)) {
|
|
6531
6913
|
console.error(`${RED7}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
|
|
6532
6914
|
process.exitCode = 1;
|
|
6533
6915
|
return;
|
|
6534
6916
|
}
|
|
6535
6917
|
let essence;
|
|
6536
6918
|
try {
|
|
6537
|
-
const raw =
|
|
6919
|
+
const raw = readFileSync18(essencePath, "utf-8");
|
|
6538
6920
|
const parsed = JSON.parse(raw);
|
|
6539
6921
|
if (!isV46(parsed)) {
|
|
6540
6922
|
console.error(
|
|
@@ -6560,7 +6942,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
|
|
|
6560
6942
|
return;
|
|
6561
6943
|
}
|
|
6562
6944
|
const registryClient = new RegistryClient({
|
|
6563
|
-
cacheDir:
|
|
6945
|
+
cacheDir: join26(projectRoot, ".decantr", "cache"),
|
|
6564
6946
|
offline: options.offline
|
|
6565
6947
|
});
|
|
6566
6948
|
console.log("Regenerating derived files...\n");
|
|
@@ -6591,8 +6973,8 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
|
|
|
6591
6973
|
}
|
|
6592
6974
|
|
|
6593
6975
|
// src/commands/registry-mirror.ts
|
|
6594
|
-
import { mkdirSync as
|
|
6595
|
-
import { join as
|
|
6976
|
+
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
6977
|
+
import { join as join27 } from "path";
|
|
6596
6978
|
import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
|
|
6597
6979
|
var GREEN10 = "\x1B[32m";
|
|
6598
6980
|
var RED8 = "\x1B[31m";
|
|
@@ -6620,7 +7002,7 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
|
|
|
6620
7002
|
process.exitCode = 1;
|
|
6621
7003
|
return;
|
|
6622
7004
|
}
|
|
6623
|
-
const cacheDir =
|
|
7005
|
+
const cacheDir = join27(projectRoot, ".decantr", "cache");
|
|
6624
7006
|
const counts = {};
|
|
6625
7007
|
const failed = [];
|
|
6626
7008
|
console.log(`
|
|
@@ -6630,19 +7012,19 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
|
|
|
6630
7012
|
try {
|
|
6631
7013
|
const result = await apiClient.listContent(type, { namespace: "@official" });
|
|
6632
7014
|
const items = result.items;
|
|
6633
|
-
const typeDir =
|
|
6634
|
-
|
|
6635
|
-
|
|
7015
|
+
const typeDir = join27(cacheDir, "@official", type);
|
|
7016
|
+
mkdirSync15(typeDir, { recursive: true });
|
|
7017
|
+
writeFileSync15(join27(typeDir, "index.json"), JSON.stringify(result, null, 2));
|
|
6636
7018
|
let itemCount = 0;
|
|
6637
7019
|
for (const item of items) {
|
|
6638
7020
|
const slug = item.slug || item.id;
|
|
6639
7021
|
if (!slug) continue;
|
|
6640
7022
|
try {
|
|
6641
7023
|
const fullItem = await apiClient.getContent(type, "@official", slug);
|
|
6642
|
-
|
|
7024
|
+
writeFileSync15(join27(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
|
|
6643
7025
|
itemCount++;
|
|
6644
7026
|
} catch {
|
|
6645
|
-
|
|
7027
|
+
writeFileSync15(join27(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
|
|
6646
7028
|
itemCount++;
|
|
6647
7029
|
}
|
|
6648
7030
|
}
|
|
@@ -6657,8 +7039,8 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
|
|
|
6657
7039
|
mirrored_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6658
7040
|
counts
|
|
6659
7041
|
};
|
|
6660
|
-
|
|
6661
|
-
|
|
7042
|
+
mkdirSync15(join27(cacheDir), { recursive: true });
|
|
7043
|
+
writeFileSync15(join27(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
|
|
6662
7044
|
const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
|
|
6663
7045
|
console.log("");
|
|
6664
7046
|
if (failed.length > 0) {
|
|
@@ -6675,8 +7057,8 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
|
|
|
6675
7057
|
}
|
|
6676
7058
|
|
|
6677
7059
|
// src/commands/remove.ts
|
|
6678
|
-
import { existsSync as
|
|
6679
|
-
import { join as
|
|
7060
|
+
import { existsSync as existsSync26, readFileSync as readFileSync19, rmSync as rmSync2, writeFileSync as writeFileSync16 } from "fs";
|
|
7061
|
+
import { join as join28 } from "path";
|
|
6680
7062
|
import { isV4 as isV47 } from "@decantr/essence-spec";
|
|
6681
7063
|
var GREEN11 = "\x1B[32m";
|
|
6682
7064
|
var RED9 = "\x1B[31m";
|
|
@@ -6684,15 +7066,15 @@ var YELLOW8 = "\x1B[33m";
|
|
|
6684
7066
|
var DIM11 = "\x1B[2m";
|
|
6685
7067
|
var RESET11 = "\x1B[0m";
|
|
6686
7068
|
function readV4Essence2(projectRoot) {
|
|
6687
|
-
const essencePath =
|
|
6688
|
-
if (!
|
|
7069
|
+
const essencePath = join28(projectRoot, "decantr.essence.json");
|
|
7070
|
+
if (!existsSync26(essencePath)) {
|
|
6689
7071
|
console.error(`${RED9}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
|
|
6690
7072
|
process.exitCode = 1;
|
|
6691
7073
|
return null;
|
|
6692
7074
|
}
|
|
6693
7075
|
let parsed;
|
|
6694
7076
|
try {
|
|
6695
|
-
parsed = JSON.parse(
|
|
7077
|
+
parsed = JSON.parse(readFileSync19(essencePath, "utf-8"));
|
|
6696
7078
|
} catch (e) {
|
|
6697
7079
|
console.error(`${RED9}Could not read essence: ${e.message}${RESET11}`);
|
|
6698
7080
|
process.exitCode = 1;
|
|
@@ -6708,7 +7090,7 @@ function readV4Essence2(projectRoot) {
|
|
|
6708
7090
|
return { essence: parsed, essencePath };
|
|
6709
7091
|
}
|
|
6710
7092
|
function writeEssence2(essencePath, essence) {
|
|
6711
|
-
|
|
7093
|
+
writeFileSync16(essencePath, JSON.stringify(essence, null, 2) + "\n");
|
|
6712
7094
|
}
|
|
6713
7095
|
function readFlagValue2(args, name) {
|
|
6714
7096
|
const prefix = `--${name}=`;
|
|
@@ -6780,14 +7162,14 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
|
|
|
6780
7162
|
sections.splice(idx, 1);
|
|
6781
7163
|
recomputeGlobalFeatures(essence);
|
|
6782
7164
|
removeRoutes(essence, sectionId);
|
|
6783
|
-
const contextFile =
|
|
6784
|
-
if (
|
|
7165
|
+
const contextFile = join28(projectRoot, ".decantr", "context", `${sectionId}.md`);
|
|
7166
|
+
if (existsSync26(contextFile)) {
|
|
6785
7167
|
rmSync2(contextFile);
|
|
6786
7168
|
}
|
|
6787
7169
|
writeEssence2(essencePath, essence);
|
|
6788
7170
|
console.log(`${GREEN11}Removed section "${sectionId}".${RESET11}`);
|
|
6789
7171
|
const registryClient = new RegistryClient({
|
|
6790
|
-
cacheDir:
|
|
7172
|
+
cacheDir: join28(projectRoot, ".decantr", "cache")
|
|
6791
7173
|
});
|
|
6792
7174
|
await refreshDerivedFiles(projectRoot, essence, registryClient);
|
|
6793
7175
|
console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
|
|
@@ -6830,7 +7212,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
|
|
|
6830
7212
|
}
|
|
6831
7213
|
console.log(`${GREEN11}Removed page "${pageId}" from section "${resolvedSectionId}".${RESET11}`);
|
|
6832
7214
|
const registryClient = new RegistryClient({
|
|
6833
|
-
cacheDir:
|
|
7215
|
+
cacheDir: join28(projectRoot, ".decantr", "cache")
|
|
6834
7216
|
});
|
|
6835
7217
|
await refreshDerivedFiles(projectRoot, essence, registryClient);
|
|
6836
7218
|
console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
|
|
@@ -6873,15 +7255,15 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
|
|
|
6873
7255
|
const target = sectionId ? `section "${sectionId}" and global` : "global";
|
|
6874
7256
|
console.log(`${GREEN11}Removed feature "${feature}" from ${target} features.${RESET11}`);
|
|
6875
7257
|
const registryClient = new RegistryClient({
|
|
6876
|
-
cacheDir:
|
|
7258
|
+
cacheDir: join28(projectRoot, ".decantr", "cache")
|
|
6877
7259
|
});
|
|
6878
7260
|
await refreshDerivedFiles(projectRoot, essence, registryClient);
|
|
6879
7261
|
console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
|
|
6880
7262
|
}
|
|
6881
7263
|
|
|
6882
7264
|
// src/commands/sync-drift.ts
|
|
6883
|
-
import { existsSync as
|
|
6884
|
-
import { join as
|
|
7265
|
+
import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "fs";
|
|
7266
|
+
import { join as join29 } from "path";
|
|
6885
7267
|
var GREEN12 = "\x1B[32m";
|
|
6886
7268
|
var RED10 = "\x1B[31m";
|
|
6887
7269
|
var YELLOW9 = "\x1B[33m";
|
|
@@ -6890,8 +7272,8 @@ var DIM12 = "\x1B[2m";
|
|
|
6890
7272
|
var BOLD6 = "\x1B[1m";
|
|
6891
7273
|
var CYAN6 = "\x1B[36m";
|
|
6892
7274
|
async function cmdSyncDrift(projectRoot = process.cwd()) {
|
|
6893
|
-
const driftLogPath =
|
|
6894
|
-
if (!
|
|
7275
|
+
const driftLogPath = join29(projectRoot, ".decantr", "drift-log.json");
|
|
7276
|
+
if (!existsSync27(driftLogPath)) {
|
|
6895
7277
|
console.log(`${GREEN12}No drift log found \u2014 no drift recorded.${RESET12}`);
|
|
6896
7278
|
console.log(
|
|
6897
7279
|
`${DIM12}Drift is logged when guard violations are detected during development.${RESET12}`
|
|
@@ -6900,7 +7282,7 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
|
|
|
6900
7282
|
}
|
|
6901
7283
|
let entries;
|
|
6902
7284
|
try {
|
|
6903
|
-
entries = JSON.parse(
|
|
7285
|
+
entries = JSON.parse(readFileSync20(driftLogPath, "utf-8"));
|
|
6904
7286
|
} catch {
|
|
6905
7287
|
console.error(`${RED10}Could not parse drift-log.json${RESET12}`);
|
|
6906
7288
|
process.exitCode = 1;
|
|
@@ -6946,13 +7328,13 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
|
|
|
6946
7328
|
console.log("");
|
|
6947
7329
|
}
|
|
6948
7330
|
function resolveDriftEntries(projectRoot, options) {
|
|
6949
|
-
const driftLogPath =
|
|
6950
|
-
if (!
|
|
7331
|
+
const driftLogPath = join29(projectRoot, ".decantr", "drift-log.json");
|
|
7332
|
+
if (!existsSync27(driftLogPath)) {
|
|
6951
7333
|
return { success: true };
|
|
6952
7334
|
}
|
|
6953
7335
|
if (options.clear) {
|
|
6954
7336
|
try {
|
|
6955
|
-
|
|
7337
|
+
writeFileSync17(driftLogPath, "[]");
|
|
6956
7338
|
return { success: true };
|
|
6957
7339
|
} catch (e) {
|
|
6958
7340
|
return { success: false, error: `Could not clear drift log: ${e.message}` };
|
|
@@ -6960,7 +7342,7 @@ function resolveDriftEntries(projectRoot, options) {
|
|
|
6960
7342
|
}
|
|
6961
7343
|
let entries;
|
|
6962
7344
|
try {
|
|
6963
|
-
entries = JSON.parse(
|
|
7345
|
+
entries = JSON.parse(readFileSync20(driftLogPath, "utf-8"));
|
|
6964
7346
|
} catch {
|
|
6965
7347
|
return { success: false, error: "Could not parse drift-log.json" };
|
|
6966
7348
|
}
|
|
@@ -6979,7 +7361,7 @@ function resolveDriftEntries(projectRoot, options) {
|
|
|
6979
7361
|
}
|
|
6980
7362
|
}
|
|
6981
7363
|
try {
|
|
6982
|
-
|
|
7364
|
+
writeFileSync17(driftLogPath, JSON.stringify(entries, null, 2));
|
|
6983
7365
|
return { success: true };
|
|
6984
7366
|
} catch (e) {
|
|
6985
7367
|
return { success: false, error: `Could not write drift log: ${e.message}` };
|
|
@@ -7204,8 +7586,8 @@ function trimTrailingSlashes(value) {
|
|
|
7204
7586
|
}
|
|
7205
7587
|
|
|
7206
7588
|
// src/commands/theme-switch.ts
|
|
7207
|
-
import { existsSync as
|
|
7208
|
-
import { join as
|
|
7589
|
+
import { existsSync as existsSync28, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
|
|
7590
|
+
import { join as join30 } from "path";
|
|
7209
7591
|
import { isV4 as isV48 } from "@decantr/essence-spec";
|
|
7210
7592
|
var GREEN14 = "\x1B[32m";
|
|
7211
7593
|
var RED11 = "\x1B[31m";
|
|
@@ -7222,15 +7604,15 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
7222
7604
|
process.exitCode = 1;
|
|
7223
7605
|
return;
|
|
7224
7606
|
}
|
|
7225
|
-
const essencePath =
|
|
7226
|
-
if (!
|
|
7607
|
+
const essencePath = join30(projectRoot, "decantr.essence.json");
|
|
7608
|
+
if (!existsSync28(essencePath)) {
|
|
7227
7609
|
console.error(`${RED11}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
|
|
7228
7610
|
process.exitCode = 1;
|
|
7229
7611
|
return;
|
|
7230
7612
|
}
|
|
7231
7613
|
let parsed;
|
|
7232
7614
|
try {
|
|
7233
|
-
parsed = JSON.parse(
|
|
7615
|
+
parsed = JSON.parse(readFileSync21(essencePath, "utf-8"));
|
|
7234
7616
|
} catch (e) {
|
|
7235
7617
|
console.error(`${RED11}Could not read essence: ${e.message}${RESET14}`);
|
|
7236
7618
|
process.exitCode = 1;
|
|
@@ -7281,7 +7663,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
7281
7663
|
essence.dna.theme.mode = mode;
|
|
7282
7664
|
}
|
|
7283
7665
|
const registryClient = new RegistryClient({
|
|
7284
|
-
cacheDir:
|
|
7666
|
+
cacheDir: join30(projectRoot, ".decantr", "cache")
|
|
7285
7667
|
});
|
|
7286
7668
|
try {
|
|
7287
7669
|
const themeResult = await registryClient.fetchTheme(themeName);
|
|
@@ -7296,7 +7678,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
7296
7678
|
}
|
|
7297
7679
|
} catch {
|
|
7298
7680
|
}
|
|
7299
|
-
|
|
7681
|
+
writeFileSync18(essencePath, JSON.stringify(essence, null, 2) + "\n");
|
|
7300
7682
|
console.log(`${GREEN14}Switched theme: ${oldThemeId} \u2192 ${themeName}${RESET14}`);
|
|
7301
7683
|
if (shape) console.log(` ${DIM14}Shape: ${shape}${RESET14}`);
|
|
7302
7684
|
if (mode) console.log(` ${DIM14}Mode: ${mode}${RESET14}`);
|
|
@@ -7604,8 +7986,8 @@ async function runSimplifiedInit(blueprints) {
|
|
|
7604
7986
|
}
|
|
7605
7987
|
|
|
7606
7988
|
// src/theme-commands.ts
|
|
7607
|
-
import { existsSync as
|
|
7608
|
-
import { join as
|
|
7989
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync8, readFileSync as readFileSync22, rmSync as rmSync3, writeFileSync as writeFileSync19 } from "fs";
|
|
7990
|
+
import { join as join31 } from "path";
|
|
7609
7991
|
var REQUIRED_FIELDS = [
|
|
7610
7992
|
"$schema",
|
|
7611
7993
|
"id",
|
|
@@ -7665,20 +8047,20 @@ function validateCustomTheme(theme) {
|
|
|
7665
8047
|
};
|
|
7666
8048
|
}
|
|
7667
8049
|
function createTheme(projectRoot, id, name) {
|
|
7668
|
-
const customThemesDir =
|
|
7669
|
-
const themePath =
|
|
7670
|
-
const howToPath =
|
|
7671
|
-
|
|
7672
|
-
if (
|
|
8050
|
+
const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
|
|
8051
|
+
const themePath = join31(customThemesDir, `${id}.json`);
|
|
8052
|
+
const howToPath = join31(customThemesDir, "how-to-theme.md");
|
|
8053
|
+
mkdirSync16(customThemesDir, { recursive: true });
|
|
8054
|
+
if (existsSync29(themePath)) {
|
|
7673
8055
|
return {
|
|
7674
8056
|
success: false,
|
|
7675
8057
|
error: `Theme "${id}" already exists at ${themePath}`
|
|
7676
8058
|
};
|
|
7677
8059
|
}
|
|
7678
8060
|
const skeleton = getThemeSkeleton(id, name);
|
|
7679
|
-
|
|
7680
|
-
if (!
|
|
7681
|
-
|
|
8061
|
+
writeFileSync19(themePath, JSON.stringify(skeleton, null, 2));
|
|
8062
|
+
if (!existsSync29(howToPath)) {
|
|
8063
|
+
writeFileSync19(howToPath, getHowToThemeDoc());
|
|
7682
8064
|
}
|
|
7683
8065
|
return {
|
|
7684
8066
|
success: true,
|
|
@@ -7686,17 +8068,17 @@ function createTheme(projectRoot, id, name) {
|
|
|
7686
8068
|
};
|
|
7687
8069
|
}
|
|
7688
8070
|
function listCustomThemes(projectRoot) {
|
|
7689
|
-
const customThemesDir =
|
|
7690
|
-
if (!
|
|
8071
|
+
const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
|
|
8072
|
+
if (!existsSync29(customThemesDir)) {
|
|
7691
8073
|
return [];
|
|
7692
8074
|
}
|
|
7693
8075
|
const themes = [];
|
|
7694
8076
|
try {
|
|
7695
8077
|
const files = readdirSync8(customThemesDir).filter((f) => f.endsWith(".json"));
|
|
7696
8078
|
for (const file of files) {
|
|
7697
|
-
const filePath =
|
|
8079
|
+
const filePath = join31(customThemesDir, file);
|
|
7698
8080
|
try {
|
|
7699
|
-
const data = JSON.parse(
|
|
8081
|
+
const data = JSON.parse(readFileSync22(filePath, "utf-8"));
|
|
7700
8082
|
themes.push({
|
|
7701
8083
|
id: data.id || file.replace(".json", ""),
|
|
7702
8084
|
name: data.name || data.id,
|
|
@@ -7711,8 +8093,8 @@ function listCustomThemes(projectRoot) {
|
|
|
7711
8093
|
return themes;
|
|
7712
8094
|
}
|
|
7713
8095
|
function deleteTheme(projectRoot, id) {
|
|
7714
|
-
const themePath =
|
|
7715
|
-
if (!
|
|
8096
|
+
const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
|
|
8097
|
+
if (!existsSync29(themePath)) {
|
|
7716
8098
|
return {
|
|
7717
8099
|
success: false,
|
|
7718
8100
|
error: `Theme "${id}" not found at ${themePath}`
|
|
@@ -7729,7 +8111,7 @@ function deleteTheme(projectRoot, id) {
|
|
|
7729
8111
|
}
|
|
7730
8112
|
}
|
|
7731
8113
|
function importTheme(projectRoot, sourcePath) {
|
|
7732
|
-
if (!
|
|
8114
|
+
if (!existsSync29(sourcePath)) {
|
|
7733
8115
|
return {
|
|
7734
8116
|
success: false,
|
|
7735
8117
|
errors: [`Source file not found: ${sourcePath}`]
|
|
@@ -7737,7 +8119,7 @@ function importTheme(projectRoot, sourcePath) {
|
|
|
7737
8119
|
}
|
|
7738
8120
|
let theme;
|
|
7739
8121
|
try {
|
|
7740
|
-
theme = JSON.parse(
|
|
8122
|
+
theme = JSON.parse(readFileSync22(sourcePath, "utf-8"));
|
|
7741
8123
|
} catch (e) {
|
|
7742
8124
|
return {
|
|
7743
8125
|
success: false,
|
|
@@ -7753,14 +8135,14 @@ function importTheme(projectRoot, sourcePath) {
|
|
|
7753
8135
|
}
|
|
7754
8136
|
theme.source = "custom";
|
|
7755
8137
|
const id = theme.id;
|
|
7756
|
-
const customThemesDir =
|
|
7757
|
-
const destPath =
|
|
7758
|
-
|
|
7759
|
-
const howToPath =
|
|
7760
|
-
if (!
|
|
7761
|
-
|
|
7762
|
-
}
|
|
7763
|
-
|
|
8138
|
+
const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
|
|
8139
|
+
const destPath = join31(customThemesDir, `${id}.json`);
|
|
8140
|
+
mkdirSync16(customThemesDir, { recursive: true });
|
|
8141
|
+
const howToPath = join31(customThemesDir, "how-to-theme.md");
|
|
8142
|
+
if (!existsSync29(howToPath)) {
|
|
8143
|
+
writeFileSync19(howToPath, getHowToThemeDoc());
|
|
8144
|
+
}
|
|
8145
|
+
writeFileSync19(destPath, JSON.stringify(theme, null, 2));
|
|
7764
8146
|
return {
|
|
7765
8147
|
success: true,
|
|
7766
8148
|
path: destPath
|
|
@@ -8307,18 +8689,18 @@ function extractHostedAssetPaths(indexHtml) {
|
|
|
8307
8689
|
return [...assetPaths];
|
|
8308
8690
|
}
|
|
8309
8691
|
function readHostedDistSnapshot(distPath) {
|
|
8310
|
-
const resolvedDistPath = distPath ? resolveUserPath(distPath) :
|
|
8311
|
-
const indexPath =
|
|
8312
|
-
if (!
|
|
8692
|
+
const resolvedDistPath = distPath ? resolveUserPath(distPath) : join32(process.cwd(), "dist");
|
|
8693
|
+
const indexPath = join32(resolvedDistPath, "index.html");
|
|
8694
|
+
if (!existsSync30(indexPath)) {
|
|
8313
8695
|
return void 0;
|
|
8314
8696
|
}
|
|
8315
|
-
const indexHtml =
|
|
8697
|
+
const indexHtml = readFileSync23(indexPath, "utf-8");
|
|
8316
8698
|
const assetPaths = extractHostedAssetPaths(indexHtml);
|
|
8317
8699
|
const assets = {};
|
|
8318
8700
|
for (const assetPath of assetPaths) {
|
|
8319
|
-
const assetFilePath =
|
|
8320
|
-
if (
|
|
8321
|
-
assets[assetPath] =
|
|
8701
|
+
const assetFilePath = join32(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
|
|
8702
|
+
if (existsSync30(assetFilePath)) {
|
|
8703
|
+
assets[assetPath] = readFileSync23(assetFilePath, "utf-8");
|
|
8322
8704
|
}
|
|
8323
8705
|
}
|
|
8324
8706
|
return {
|
|
@@ -8333,7 +8715,7 @@ function isHostedSourceSnapshotFile(path) {
|
|
|
8333
8715
|
function readHostedSourceSnapshot(sourcePath) {
|
|
8334
8716
|
if (!sourcePath) return void 0;
|
|
8335
8717
|
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
8336
|
-
if (!
|
|
8718
|
+
if (!existsSync30(resolvedSourcePath)) {
|
|
8337
8719
|
return void 0;
|
|
8338
8720
|
}
|
|
8339
8721
|
const files = {};
|
|
@@ -8349,15 +8731,15 @@ function readHostedSourceSnapshot(sourcePath) {
|
|
|
8349
8731
|
const walk = (absoluteDir, relativeDir) => {
|
|
8350
8732
|
for (const entry of readdirSync9(absoluteDir, { withFileTypes: true })) {
|
|
8351
8733
|
if (ignoredDirNames.has(entry.name)) continue;
|
|
8352
|
-
const absolutePath =
|
|
8353
|
-
const relativePath =
|
|
8734
|
+
const absolutePath = join32(absoluteDir, entry.name);
|
|
8735
|
+
const relativePath = join32(relativeDir, entry.name).replace(/\\/g, "/");
|
|
8354
8736
|
if (entry.isDirectory()) {
|
|
8355
8737
|
walk(absolutePath, relativePath);
|
|
8356
8738
|
continue;
|
|
8357
8739
|
}
|
|
8358
8740
|
if (!entry.isFile()) continue;
|
|
8359
8741
|
if (!isHostedSourceSnapshotFile(relativePath)) continue;
|
|
8360
|
-
files[relativePath] =
|
|
8742
|
+
files[relativePath] = readFileSync23(absolutePath, "utf-8");
|
|
8361
8743
|
}
|
|
8362
8744
|
};
|
|
8363
8745
|
walk(resolvedSourcePath, rootPrefix);
|
|
@@ -8550,24 +8932,24 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
|
|
|
8550
8932
|
}
|
|
8551
8933
|
async function compileHostedExecutionPackBundle(essencePath, namespace) {
|
|
8552
8934
|
const client = getPublicAPIClient();
|
|
8553
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
8554
|
-
if (!
|
|
8935
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
8936
|
+
if (!existsSync30(resolvedPath)) {
|
|
8555
8937
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
8556
8938
|
}
|
|
8557
|
-
const essence = JSON.parse(
|
|
8939
|
+
const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
|
|
8558
8940
|
const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
|
|
8559
|
-
const contextDir =
|
|
8941
|
+
const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
|
|
8560
8942
|
return { resolvedPath, bundle, contextDir };
|
|
8561
8943
|
}
|
|
8562
8944
|
function writeHostedExecutionPackContextArtifacts(contextDir, bundle) {
|
|
8563
|
-
|
|
8945
|
+
mkdirSync17(contextDir, { recursive: true });
|
|
8564
8946
|
return writeExecutionPackBundleArtifacts(contextDir, bundle);
|
|
8565
8947
|
}
|
|
8566
8948
|
function resolvePagePackIdForRoute(essencePath, route) {
|
|
8567
|
-
if (!
|
|
8949
|
+
if (!existsSync30(essencePath)) {
|
|
8568
8950
|
throw new Error(`Essence file not found at ${essencePath}`);
|
|
8569
8951
|
}
|
|
8570
|
-
const essence = JSON.parse(
|
|
8952
|
+
const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
|
|
8571
8953
|
if (!isV49(essence)) {
|
|
8572
8954
|
throw new Error("Route-based pack resolution requires Essence v4.0.0.");
|
|
8573
8955
|
}
|
|
@@ -8582,14 +8964,14 @@ function resolvePagePackIdForRoute(essencePath, route) {
|
|
|
8582
8964
|
}
|
|
8583
8965
|
async function printHostedSelectedExecutionPack(packType, id, essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
8584
8966
|
const client = getPublicAPIClient();
|
|
8585
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
8586
|
-
if (!
|
|
8967
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
8968
|
+
if (!existsSync30(resolvedPath)) {
|
|
8587
8969
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
8588
8970
|
}
|
|
8589
8971
|
if ((packType === "section" || packType === "page" || packType === "mutation") && !id) {
|
|
8590
8972
|
throw new Error(`Pack type "${packType}" requires an id.`);
|
|
8591
8973
|
}
|
|
8592
|
-
const essence = JSON.parse(
|
|
8974
|
+
const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
|
|
8593
8975
|
const selected = await client.selectExecutionPack(
|
|
8594
8976
|
{
|
|
8595
8977
|
essence,
|
|
@@ -8600,17 +8982,17 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
|
|
|
8600
8982
|
);
|
|
8601
8983
|
let writtenContextDir = null;
|
|
8602
8984
|
if (writeContext) {
|
|
8603
|
-
const contextDir =
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8985
|
+
const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
|
|
8986
|
+
mkdirSync17(contextDir, { recursive: true });
|
|
8987
|
+
writeFileSync20(
|
|
8988
|
+
join32(contextDir, "pack-manifest.json"),
|
|
8607
8989
|
JSON.stringify(selected.manifest, null, 2) + "\n"
|
|
8608
8990
|
);
|
|
8609
8991
|
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);
|
|
8610
8992
|
const markdownFile = manifestEntry?.markdown ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.md`;
|
|
8611
8993
|
const jsonFile = manifestEntry?.json ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.json`;
|
|
8612
|
-
|
|
8613
|
-
|
|
8994
|
+
writeFileSync20(join32(contextDir, markdownFile), selected.pack.renderedMarkdown);
|
|
8995
|
+
writeFileSync20(join32(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
|
|
8614
8996
|
writtenContextDir = contextDir;
|
|
8615
8997
|
}
|
|
8616
8998
|
if (jsonOutput) {
|
|
@@ -8635,20 +9017,20 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
|
|
|
8635
9017
|
}
|
|
8636
9018
|
async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
8637
9019
|
const client = getPublicAPIClient();
|
|
8638
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
8639
|
-
if (!
|
|
9020
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
9021
|
+
if (!existsSync30(resolvedPath)) {
|
|
8640
9022
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
8641
9023
|
}
|
|
8642
|
-
const essence = JSON.parse(
|
|
9024
|
+
const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
|
|
8643
9025
|
const manifest = await client.getExecutionPackManifest(
|
|
8644
9026
|
essence,
|
|
8645
9027
|
namespace ? { namespace } : void 0
|
|
8646
9028
|
);
|
|
8647
9029
|
let writtenContextDir = null;
|
|
8648
9030
|
if (writeContext) {
|
|
8649
|
-
const contextDir =
|
|
8650
|
-
|
|
8651
|
-
|
|
9031
|
+
const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
|
|
9032
|
+
mkdirSync17(contextDir, { recursive: true });
|
|
9033
|
+
writeFileSync20(join32(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
8652
9034
|
writtenContextDir = contextDir;
|
|
8653
9035
|
}
|
|
8654
9036
|
if (jsonOutput) {
|
|
@@ -8669,14 +9051,14 @@ async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutp
|
|
|
8669
9051
|
}
|
|
8670
9052
|
}
|
|
8671
9053
|
async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@official") {
|
|
8672
|
-
const contextDir =
|
|
8673
|
-
const reviewPackPath =
|
|
8674
|
-
const manifestPath =
|
|
8675
|
-
if (
|
|
9054
|
+
const contextDir = join32(projectRoot, ".decantr", "context");
|
|
9055
|
+
const reviewPackPath = join32(contextDir, "review-pack.json");
|
|
9056
|
+
const manifestPath = join32(contextDir, "pack-manifest.json");
|
|
9057
|
+
if (existsSync30(reviewPackPath) && existsSync30(manifestPath)) {
|
|
8676
9058
|
return { attempted: false, hydrated: false };
|
|
8677
9059
|
}
|
|
8678
|
-
const essencePath =
|
|
8679
|
-
if (!
|
|
9060
|
+
const essencePath = join32(projectRoot, "decantr.essence.json");
|
|
9061
|
+
if (!existsSync30(essencePath)) {
|
|
8680
9062
|
return { attempted: false, hydrated: false };
|
|
8681
9063
|
}
|
|
8682
9064
|
const reviewHydration = await hydrateHostedReviewPackIfMissing(projectRoot, namespace);
|
|
@@ -8685,9 +9067,9 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
|
|
|
8685
9067
|
}
|
|
8686
9068
|
try {
|
|
8687
9069
|
const client = getPublicAPIClient();
|
|
8688
|
-
const essence = JSON.parse(
|
|
9070
|
+
const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
|
|
8689
9071
|
const bundle = await client.compileExecutionPacks(essence, { namespace });
|
|
8690
|
-
|
|
9072
|
+
mkdirSync17(contextDir, { recursive: true });
|
|
8691
9073
|
writeExecutionPackBundleArtifacts(contextDir, bundle);
|
|
8692
9074
|
return { attempted: true, hydrated: true, scope: "bundle" };
|
|
8693
9075
|
} catch {
|
|
@@ -8695,19 +9077,19 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
|
|
|
8695
9077
|
}
|
|
8696
9078
|
}
|
|
8697
9079
|
async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@official") {
|
|
8698
|
-
const contextDir =
|
|
8699
|
-
const reviewPackPath =
|
|
8700
|
-
const manifestPath =
|
|
8701
|
-
if (
|
|
9080
|
+
const contextDir = join32(projectRoot, ".decantr", "context");
|
|
9081
|
+
const reviewPackPath = join32(contextDir, "review-pack.json");
|
|
9082
|
+
const manifestPath = join32(contextDir, "pack-manifest.json");
|
|
9083
|
+
if (existsSync30(reviewPackPath) && existsSync30(manifestPath)) {
|
|
8702
9084
|
return { attempted: false, hydrated: false };
|
|
8703
9085
|
}
|
|
8704
|
-
const essencePath =
|
|
8705
|
-
if (!
|
|
9086
|
+
const essencePath = join32(projectRoot, "decantr.essence.json");
|
|
9087
|
+
if (!existsSync30(essencePath)) {
|
|
8706
9088
|
return { attempted: false, hydrated: false };
|
|
8707
9089
|
}
|
|
8708
9090
|
try {
|
|
8709
9091
|
const client = getPublicAPIClient();
|
|
8710
|
-
const essence = JSON.parse(
|
|
9092
|
+
const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
|
|
8711
9093
|
const selected = await client.selectExecutionPack(
|
|
8712
9094
|
{
|
|
8713
9095
|
essence,
|
|
@@ -8715,14 +9097,14 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
|
|
|
8715
9097
|
},
|
|
8716
9098
|
{ namespace }
|
|
8717
9099
|
);
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
9100
|
+
mkdirSync17(contextDir, { recursive: true });
|
|
9101
|
+
writeFileSync20(join32(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
|
|
9102
|
+
writeFileSync20(
|
|
9103
|
+
join32(contextDir, "review-pack.json"),
|
|
8722
9104
|
JSON.stringify(selected.pack, null, 2) + "\n"
|
|
8723
9105
|
);
|
|
8724
|
-
if (!
|
|
8725
|
-
|
|
9106
|
+
if (!existsSync30(manifestPath)) {
|
|
9107
|
+
writeFileSync20(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
|
|
8726
9108
|
}
|
|
8727
9109
|
return { attempted: true, hydrated: true, scope: "review" };
|
|
8728
9110
|
} catch {
|
|
@@ -8732,17 +9114,17 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
|
|
|
8732
9114
|
async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false, essencePath, treatmentsPath) {
|
|
8733
9115
|
const client = getPublicAPIClient();
|
|
8734
9116
|
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
8735
|
-
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) :
|
|
8736
|
-
const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) :
|
|
8737
|
-
if (!
|
|
9117
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
9118
|
+
const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join32(process.cwd(), "src", "styles", "treatments.css");
|
|
9119
|
+
if (!existsSync30(resolvedSourcePath)) {
|
|
8738
9120
|
throw new Error(`Source file not found at ${resolvedSourcePath}`);
|
|
8739
9121
|
}
|
|
8740
|
-
if (!
|
|
9122
|
+
if (!existsSync30(resolvedEssencePath)) {
|
|
8741
9123
|
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
8742
9124
|
}
|
|
8743
|
-
const code =
|
|
8744
|
-
const essence = JSON.parse(
|
|
8745
|
-
const treatmentsCss =
|
|
9125
|
+
const code = readFileSync23(resolvedSourcePath, "utf-8");
|
|
9126
|
+
const essence = JSON.parse(readFileSync23(resolvedEssencePath, "utf-8"));
|
|
9127
|
+
const treatmentsCss = existsSync30(resolvedTreatmentsPath) ? readFileSync23(resolvedTreatmentsPath, "utf-8") : void 0;
|
|
8746
9128
|
const report = await client.critiqueFile(
|
|
8747
9129
|
{
|
|
8748
9130
|
essence,
|
|
@@ -8766,11 +9148,11 @@ async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false
|
|
|
8766
9148
|
}
|
|
8767
9149
|
async function printHostedProjectAudit(namespace, jsonOutput = false, essencePath, distPath, sourcesPath) {
|
|
8768
9150
|
const client = getPublicAPIClient();
|
|
8769
|
-
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) :
|
|
8770
|
-
if (!
|
|
9151
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
9152
|
+
if (!existsSync30(resolvedEssencePath)) {
|
|
8771
9153
|
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
8772
9154
|
}
|
|
8773
|
-
const essence = JSON.parse(
|
|
9155
|
+
const essence = JSON.parse(readFileSync23(resolvedEssencePath, "utf-8"));
|
|
8774
9156
|
const dist = readHostedDistSnapshot(distPath);
|
|
8775
9157
|
const sources = readHostedSourceSnapshot(sourcesPath);
|
|
8776
9158
|
const report = await client.auditProject(
|
|
@@ -8788,7 +9170,7 @@ async function printHostedProjectAudit(namespace, jsonOutput = false, essencePat
|
|
|
8788
9170
|
console.log(heading2("Hosted Project Audit"));
|
|
8789
9171
|
console.log(` Essence: ${resolvedEssencePath}`);
|
|
8790
9172
|
console.log(
|
|
8791
|
-
` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) :
|
|
9173
|
+
` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join32(process.cwd(), "dist") : "none"}`
|
|
8792
9174
|
);
|
|
8793
9175
|
console.log(
|
|
8794
9176
|
` Source snapshot: ${sources && sourcesPath ? resolveUserPath(sourcesPath) : "none"}`
|
|
@@ -8891,21 +9273,21 @@ function patternCandidateFromRegistryItem(item, source) {
|
|
|
8891
9273
|
function readSuggestCodeContext(projectRoot, route, file) {
|
|
8892
9274
|
const pieces = [];
|
|
8893
9275
|
if (file) {
|
|
8894
|
-
const resolved = isAbsolute3(file) ? file :
|
|
8895
|
-
if (
|
|
8896
|
-
pieces.push(
|
|
9276
|
+
const resolved = isAbsolute3(file) ? file : join32(projectRoot, file);
|
|
9277
|
+
if (existsSync30(resolved)) {
|
|
9278
|
+
pieces.push(readFileSync23(resolved, "utf-8"));
|
|
8897
9279
|
}
|
|
8898
9280
|
}
|
|
8899
9281
|
if (route) {
|
|
8900
|
-
const analysisPath =
|
|
8901
|
-
if (
|
|
9282
|
+
const analysisPath = join32(projectRoot, ".decantr", "analysis.json");
|
|
9283
|
+
if (existsSync30(analysisPath)) {
|
|
8902
9284
|
try {
|
|
8903
|
-
const analysis = JSON.parse(
|
|
9285
|
+
const analysis = JSON.parse(readFileSync23(analysisPath, "utf-8"));
|
|
8904
9286
|
const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
|
|
8905
9287
|
if (routeEntry?.file) {
|
|
8906
|
-
const resolved =
|
|
8907
|
-
if (
|
|
8908
|
-
pieces.push(
|
|
9288
|
+
const resolved = join32(projectRoot, routeEntry.file);
|
|
9289
|
+
if (existsSync30(resolved)) {
|
|
9290
|
+
pieces.push(readFileSync23(resolved, "utf-8"));
|
|
8909
9291
|
}
|
|
8910
9292
|
}
|
|
8911
9293
|
} catch {
|
|
@@ -8989,10 +9371,11 @@ async function cmdSuggest(query, options = {}) {
|
|
|
8989
9371
|
}
|
|
8990
9372
|
}
|
|
8991
9373
|
const registryClient = new RegistryClient({
|
|
8992
|
-
cacheDir:
|
|
9374
|
+
cacheDir: join32(projectRoot, ".decantr", "cache")
|
|
8993
9375
|
});
|
|
8994
9376
|
const code = options.fromCode || options.file ? readSuggestCodeContext(projectRoot, options.route, options.file) : "";
|
|
8995
9377
|
const localMatches = localPatternMatches(projectRoot, [query, code].filter(Boolean).join("\n"));
|
|
9378
|
+
const bridgeMatches = styleBridgeMatches(projectRoot, [query, code].filter(Boolean).join("\n"));
|
|
8996
9379
|
const candidates = await loadPatternDiscoveryCandidates(registryClient);
|
|
8997
9380
|
const matches = rankPatternCandidates(
|
|
8998
9381
|
{
|
|
@@ -9003,7 +9386,7 @@ async function cmdSuggest(query, options = {}) {
|
|
|
9003
9386
|
},
|
|
9004
9387
|
candidates
|
|
9005
9388
|
);
|
|
9006
|
-
if (matches.length === 0 && localMatches.length === 0) {
|
|
9389
|
+
if (matches.length === 0 && localMatches.length === 0 && bridgeMatches.length === 0) {
|
|
9007
9390
|
console.log(dim3(`No pattern suggestions for "${query}"`));
|
|
9008
9391
|
console.log("");
|
|
9009
9392
|
console.log("Try:");
|
|
@@ -9023,6 +9406,14 @@ async function cmdSuggest(query, options = {}) {
|
|
|
9023
9406
|
`Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
|
|
9024
9407
|
)
|
|
9025
9408
|
);
|
|
9409
|
+
if (bridgeMatches.length > 0) {
|
|
9410
|
+
console.log(`${BOLD9}Project-owned style bridge:${RESET16}`);
|
|
9411
|
+
for (const match of bridgeMatches) {
|
|
9412
|
+
const hints = [...match.tokenHints, ...match.classHints].slice(0, 3).join(", ");
|
|
9413
|
+
console.log(` ${cyan3(match.id)} ${match.label}${hints ? ` ${dim3(hints)}` : ""}`);
|
|
9414
|
+
}
|
|
9415
|
+
console.log("");
|
|
9416
|
+
}
|
|
9026
9417
|
if (localMatches.length > 0) {
|
|
9027
9418
|
console.log(`${BOLD9}Project-owned local law:${RESET16}`);
|
|
9028
9419
|
for (const match of localMatches) {
|
|
@@ -9067,7 +9458,7 @@ async function cmdGet(type, id) {
|
|
|
9067
9458
|
}
|
|
9068
9459
|
const apiType = CONTENT_TYPE_TO_API_CONTENT_TYPE3[type];
|
|
9069
9460
|
const registryClient = new RegistryClient({
|
|
9070
|
-
cacheDir:
|
|
9461
|
+
cacheDir: join32(process.cwd(), ".decantr", "cache")
|
|
9071
9462
|
});
|
|
9072
9463
|
const result = await registryClient.fetchContentItem(apiType, id);
|
|
9073
9464
|
if (result) {
|
|
@@ -9084,10 +9475,10 @@ async function cmdGet(type, id) {
|
|
|
9084
9475
|
return;
|
|
9085
9476
|
}
|
|
9086
9477
|
async function cmdValidate(path) {
|
|
9087
|
-
const essencePath = path ||
|
|
9478
|
+
const essencePath = path || join32(process.cwd(), "decantr.essence.json");
|
|
9088
9479
|
let raw;
|
|
9089
9480
|
try {
|
|
9090
|
-
raw =
|
|
9481
|
+
raw = readFileSync23(essencePath, "utf-8");
|
|
9091
9482
|
} catch {
|
|
9092
9483
|
console.error(error2(`Could not read ${essencePath}`));
|
|
9093
9484
|
process.exitCode = 1;
|
|
@@ -9154,7 +9545,7 @@ async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet
|
|
|
9154
9545
|
return;
|
|
9155
9546
|
}
|
|
9156
9547
|
const registryClient = new RegistryClient({
|
|
9157
|
-
cacheDir:
|
|
9548
|
+
cacheDir: join32(process.cwd(), ".decantr", "cache")
|
|
9158
9549
|
});
|
|
9159
9550
|
const result = await registryClient.fetchContentList(
|
|
9160
9551
|
type,
|
|
@@ -9237,10 +9628,10 @@ ${CYAN9}Telemetry enabled.${RESET16} Decantr will send privacy-filtered CLI prod
|
|
|
9237
9628
|
}
|
|
9238
9629
|
function readCliPackageVersion2() {
|
|
9239
9630
|
const here = dirname6(fileURLToPath3(import.meta.url));
|
|
9240
|
-
const candidates = [
|
|
9631
|
+
const candidates = [join32(here, "..", "package.json"), join32(here, "..", "..", "package.json")];
|
|
9241
9632
|
for (const candidate of candidates) {
|
|
9242
9633
|
try {
|
|
9243
|
-
const pkg = JSON.parse(
|
|
9634
|
+
const pkg = JSON.parse(readFileSync23(candidate, "utf-8"));
|
|
9244
9635
|
if (pkg.version) return pkg.version;
|
|
9245
9636
|
} catch {
|
|
9246
9637
|
}
|
|
@@ -9251,19 +9642,19 @@ function timestampForFile() {
|
|
|
9251
9642
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9252
9643
|
}
|
|
9253
9644
|
function backupExistingEssence(projectRoot, label) {
|
|
9254
|
-
const essencePath =
|
|
9255
|
-
if (!
|
|
9256
|
-
const backupPath =
|
|
9645
|
+
const essencePath = join32(projectRoot, "decantr.essence.json");
|
|
9646
|
+
if (!existsSync30(essencePath)) return null;
|
|
9647
|
+
const backupPath = join32(
|
|
9257
9648
|
projectRoot,
|
|
9258
9649
|
`decantr.essence.${label}.${timestampForFile()}.backup.json`
|
|
9259
9650
|
);
|
|
9260
|
-
|
|
9651
|
+
writeFileSync20(backupPath, readFileSync23(essencePath, "utf-8"), "utf-8");
|
|
9261
9652
|
return backupPath;
|
|
9262
9653
|
}
|
|
9263
9654
|
function writeBrownfieldProjectJson(input) {
|
|
9264
|
-
const decantrDir =
|
|
9265
|
-
|
|
9266
|
-
|
|
9655
|
+
const decantrDir = join32(input.projectRoot, ".decantr");
|
|
9656
|
+
mkdirSync17(join32(decantrDir, "context"), { recursive: true });
|
|
9657
|
+
mkdirSync17(join32(decantrDir, "cache"), { recursive: true });
|
|
9267
9658
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9268
9659
|
const projectJson = {
|
|
9269
9660
|
detected: {
|
|
@@ -9304,7 +9695,7 @@ function writeBrownfieldProjectJson(input) {
|
|
|
9304
9695
|
}
|
|
9305
9696
|
}
|
|
9306
9697
|
};
|
|
9307
|
-
|
|
9698
|
+
writeFileSync20(join32(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
|
|
9308
9699
|
}
|
|
9309
9700
|
async function applyAcceptedBrownfieldProposal(input) {
|
|
9310
9701
|
const proposal = readBrownfieldProposal(input.projectRoot);
|
|
@@ -9320,8 +9711,8 @@ async function applyAcceptedBrownfieldProposal(input) {
|
|
|
9320
9711
|
process.exitCode = 1;
|
|
9321
9712
|
return;
|
|
9322
9713
|
}
|
|
9323
|
-
const essencePath =
|
|
9324
|
-
const hasEssence =
|
|
9714
|
+
const essencePath = join32(input.projectRoot, "decantr.essence.json");
|
|
9715
|
+
const hasEssence = existsSync30(essencePath);
|
|
9325
9716
|
let essence;
|
|
9326
9717
|
let backupPath = null;
|
|
9327
9718
|
if (input.mode === "accept" && hasEssence) {
|
|
@@ -9335,7 +9726,7 @@ async function applyAcceptedBrownfieldProposal(input) {
|
|
|
9335
9726
|
return;
|
|
9336
9727
|
}
|
|
9337
9728
|
if (input.mode === "merge" && hasEssence) {
|
|
9338
|
-
const existing = JSON.parse(
|
|
9729
|
+
const existing = JSON.parse(readFileSync23(essencePath, "utf-8"));
|
|
9339
9730
|
if (!isV49(existing)) {
|
|
9340
9731
|
console.log(
|
|
9341
9732
|
error2(
|
|
@@ -9372,9 +9763,9 @@ async function applyAcceptedBrownfieldProposal(input) {
|
|
|
9372
9763
|
assistantBridge: input.assistantBridge,
|
|
9373
9764
|
mode: input.mode
|
|
9374
9765
|
});
|
|
9375
|
-
|
|
9766
|
+
writeFileSync20(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
|
|
9376
9767
|
const registryClient = new RegistryClient({
|
|
9377
|
-
cacheDir:
|
|
9768
|
+
cacheDir: join32(input.projectRoot, ".decantr", "cache"),
|
|
9378
9769
|
offline: true,
|
|
9379
9770
|
projectRoot: input.projectRoot
|
|
9380
9771
|
});
|
|
@@ -9553,7 +9944,7 @@ async function cmdInit(args) {
|
|
|
9553
9944
|
}
|
|
9554
9945
|
}
|
|
9555
9946
|
const registryClient = new RegistryClient({
|
|
9556
|
-
cacheDir:
|
|
9947
|
+
cacheDir: join32(projectRoot, ".decantr", "cache"),
|
|
9557
9948
|
apiUrl: args.registry,
|
|
9558
9949
|
offline: args.offline,
|
|
9559
9950
|
projectRoot
|
|
@@ -9885,7 +10276,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
|
|
|
9885
10276
|
if (appliedRuleFiles.length > 0) {
|
|
9886
10277
|
console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
|
|
9887
10278
|
}
|
|
9888
|
-
if (!
|
|
10279
|
+
if (!existsSync30(join32(projectRoot, "package.json"))) {
|
|
9889
10280
|
console.log("");
|
|
9890
10281
|
console.log(
|
|
9891
10282
|
dim3(` Note: ${cyan3("decantr init")} created Decantr contract/context files only.`)
|
|
@@ -9896,7 +10287,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
|
|
|
9896
10287
|
)
|
|
9897
10288
|
);
|
|
9898
10289
|
}
|
|
9899
|
-
const hasCompiledPacks =
|
|
10290
|
+
const hasCompiledPacks = existsSync30(join32(projectRoot, ".decantr", "context", "scaffold-pack.md"));
|
|
9900
10291
|
console.log("");
|
|
9901
10292
|
console.log(" Next steps:");
|
|
9902
10293
|
if (hasCompiledPacks) {
|
|
@@ -9936,7 +10327,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
|
|
|
9936
10327
|
console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
|
|
9937
10328
|
console.log(` ${cyan3("decantr check")} Detect drift issues`);
|
|
9938
10329
|
console.log(` ${cyan3("decantr migrate --to v4")} Migrate older essence files to v4`);
|
|
9939
|
-
const essenceContent =
|
|
10330
|
+
const essenceContent = readFileSync23(result.essencePath, "utf-8");
|
|
9940
10331
|
const essence = JSON.parse(essenceContent);
|
|
9941
10332
|
const validation = validateEssence2(essence);
|
|
9942
10333
|
if (!validation.valid) {
|
|
@@ -9991,16 +10382,16 @@ Validation warnings: ${validation.errors.join(", ")}`));
|
|
|
9991
10382
|
}
|
|
9992
10383
|
}
|
|
9993
10384
|
async function cmdStatus(projectRoot = process.cwd()) {
|
|
9994
|
-
const essencePath =
|
|
9995
|
-
const projectJsonPath =
|
|
10385
|
+
const essencePath = join32(projectRoot, "decantr.essence.json");
|
|
10386
|
+
const projectJsonPath = join32(projectRoot, ".decantr", "project.json");
|
|
9996
10387
|
console.log(heading2("Decantr Project Status"));
|
|
9997
|
-
if (!
|
|
10388
|
+
if (!existsSync30(essencePath)) {
|
|
9998
10389
|
console.log(`${RED12}No decantr.essence.json found.${RESET16}`);
|
|
9999
10390
|
console.log(dim3('Run "decantr init" to create one.'));
|
|
10000
10391
|
return;
|
|
10001
10392
|
}
|
|
10002
10393
|
try {
|
|
10003
|
-
const essence = JSON.parse(
|
|
10394
|
+
const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
|
|
10004
10395
|
const validation = validateEssence2(essence);
|
|
10005
10396
|
const essenceVersion = isV49(essence) ? "v4" : "legacy";
|
|
10006
10397
|
console.log(`${BOLD9}Essence:${RESET16}`);
|
|
@@ -10048,9 +10439,9 @@ async function cmdStatus(projectRoot = process.cwd()) {
|
|
|
10048
10439
|
}
|
|
10049
10440
|
console.log("");
|
|
10050
10441
|
console.log(`${BOLD9}Sync Status:${RESET16}`);
|
|
10051
|
-
if (
|
|
10442
|
+
if (existsSync30(projectJsonPath)) {
|
|
10052
10443
|
try {
|
|
10053
|
-
const projectJson = JSON.parse(
|
|
10444
|
+
const projectJson = JSON.parse(readFileSync23(projectJsonPath, "utf-8"));
|
|
10054
10445
|
const syncStatus = projectJson.sync?.status || "unknown";
|
|
10055
10446
|
const lastSync = projectJson.sync?.lastSync || "never";
|
|
10056
10447
|
const source = projectJson.sync?.registrySource || "unknown";
|
|
@@ -10068,7 +10459,7 @@ async function cmdStatus(projectRoot = process.cwd()) {
|
|
|
10068
10459
|
}
|
|
10069
10460
|
async function cmdSync() {
|
|
10070
10461
|
const projectRoot = process.cwd();
|
|
10071
|
-
const cacheDir =
|
|
10462
|
+
const cacheDir = join32(projectRoot, ".decantr", "cache");
|
|
10072
10463
|
console.log(heading2("Syncing registry content..."));
|
|
10073
10464
|
const result = await syncRegistry(cacheDir);
|
|
10074
10465
|
if (result.synced.length > 0) {
|
|
@@ -10262,14 +10653,14 @@ ${BOLD9}Examples:${RESET16}
|
|
|
10262
10653
|
process.exitCode = 1;
|
|
10263
10654
|
return;
|
|
10264
10655
|
}
|
|
10265
|
-
const themePath =
|
|
10266
|
-
if (!
|
|
10656
|
+
const themePath = join32(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
|
|
10657
|
+
if (!existsSync30(themePath)) {
|
|
10267
10658
|
console.error(error2(`Theme "${name}" not found at ${themePath}`));
|
|
10268
10659
|
process.exitCode = 1;
|
|
10269
10660
|
return;
|
|
10270
10661
|
}
|
|
10271
10662
|
try {
|
|
10272
|
-
const theme = JSON.parse(
|
|
10663
|
+
const theme = JSON.parse(readFileSync23(themePath, "utf-8"));
|
|
10273
10664
|
const result = validateCustomTheme(theme);
|
|
10274
10665
|
if (result.valid) {
|
|
10275
10666
|
console.log(success3(`Custom theme "${name}" is valid`));
|
|
@@ -10401,7 +10792,7 @@ function withProject(command, projectArg) {
|
|
|
10401
10792
|
return projectArg ? `${command} --project ${projectArg}` : command;
|
|
10402
10793
|
}
|
|
10403
10794
|
function displayProjectPath(workspaceInfo, projectPath) {
|
|
10404
|
-
const absolutePath =
|
|
10795
|
+
const absolutePath = join32(workspaceInfo.appRoot, projectPath);
|
|
10405
10796
|
const relativePath = relative7(workspaceInfo.cwd, absolutePath).replace(/\\/g, "/");
|
|
10406
10797
|
if (relativePath && !relativePath.startsWith("..") && !isAbsolute3(relativePath)) {
|
|
10407
10798
|
return relativePath;
|
|
@@ -10460,6 +10851,7 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
|
|
|
10460
10851
|
console.log("");
|
|
10461
10852
|
console.log("Start by attaching one app:");
|
|
10462
10853
|
console.log(` ${cyan3(`decantr adopt --project ${candidate} --yes`)}`);
|
|
10854
|
+
console.log(` ${cyan3(`decantr codify --from-audit --style-bridge --project ${candidate}`)}`);
|
|
10463
10855
|
console.log("");
|
|
10464
10856
|
console.log("Optional visual evidence after the app is running:");
|
|
10465
10857
|
console.log(
|
|
@@ -10469,7 +10861,7 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
|
|
|
10469
10861
|
function printMonorepoSetupGuidance(workspaceInfo) {
|
|
10470
10862
|
const candidate = firstWorkspaceCandidate(workspaceInfo);
|
|
10471
10863
|
const attachedProjects = workspaceInfo.appCandidates.filter(
|
|
10472
|
-
(appCandidate) =>
|
|
10864
|
+
(appCandidate) => existsSync30(join32(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
|
|
10473
10865
|
);
|
|
10474
10866
|
const firstAttached = attachedProjects[0];
|
|
10475
10867
|
console.log(heading2("Decantr Setup"));
|
|
@@ -10526,7 +10918,7 @@ function printMonorepoSetupGuidance(workspaceInfo) {
|
|
|
10526
10918
|
` ${cyan3(`decantr adopt --project ${candidate} --yes`)} Attach Decantr to one app`
|
|
10527
10919
|
);
|
|
10528
10920
|
console.log(
|
|
10529
|
-
` ${cyan3(`decantr codify --from-audit --project ${candidate}`)} Propose project-owned UI law`
|
|
10921
|
+
` ${cyan3(`decantr codify --from-audit --style-bridge --project ${candidate}`)} Propose project-owned UI law and style bridge`
|
|
10530
10922
|
);
|
|
10531
10923
|
console.log("");
|
|
10532
10924
|
console.log(`${BOLD9}Optional visual evidence:${RESET16}`);
|
|
@@ -10537,7 +10929,7 @@ function printMonorepoSetupGuidance(workspaceInfo) {
|
|
|
10537
10929
|
function resolveWorkflowProject(flags, commandName = "command", options = {}) {
|
|
10538
10930
|
const projectArg = flagString(flags, "project");
|
|
10539
10931
|
const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
|
|
10540
|
-
if (projectArg && options.requireExisting !== false && !
|
|
10932
|
+
if (projectArg && options.requireExisting !== false && !existsSync30(workspaceInfo.appRoot)) {
|
|
10541
10933
|
printProjectNotFound(projectArg, commandName);
|
|
10542
10934
|
process.exitCode = 1;
|
|
10543
10935
|
return null;
|
|
@@ -10597,21 +10989,27 @@ async function cmdSetupWorkflow(args) {
|
|
|
10597
10989
|
console.log(` Detected: ${formatDetection(detected)}`);
|
|
10598
10990
|
console.log("");
|
|
10599
10991
|
if (detected.existingEssence) {
|
|
10600
|
-
const hasLocalPatterns =
|
|
10601
|
-
const hasLocalRules =
|
|
10992
|
+
const hasLocalPatterns = existsSync30(localPatternsPath(workspaceInfo.appRoot));
|
|
10993
|
+
const hasLocalRules = existsSync30(localRulesPath(workspaceInfo.appRoot));
|
|
10994
|
+
const hasStyleBridge = existsSync30(styleBridgePath(workspaceInfo.appRoot));
|
|
10602
10995
|
const verifyCommand = hasLocalPatterns || hasLocalRules ? "decantr verify --brownfield --local-patterns" : "decantr verify --brownfield";
|
|
10603
10996
|
console.log(`${BOLD9}Recommended path:${RESET16} maintain an attached Decantr project`);
|
|
10997
|
+
console.log(
|
|
10998
|
+
` ${cyan3(withProject("decantr doctor", projectArg))} Explain current state and next command`
|
|
10999
|
+
);
|
|
11000
|
+
if (!hasLocalPatterns || !hasLocalRules || !hasStyleBridge) {
|
|
11001
|
+
const codifyCommand = hasLocalPatterns && hasLocalRules ? "decantr codify --style-bridge" : "decantr codify --from-audit --style-bridge";
|
|
11002
|
+
console.log(
|
|
11003
|
+
` ${cyan3(withProject(codifyCommand, projectArg))} Propose missing local law/style bridge`
|
|
11004
|
+
);
|
|
11005
|
+
}
|
|
10604
11006
|
console.log(
|
|
10605
11007
|
` ${cyan3(withProject('decantr task <route> "<change>"', projectArg))} Prepare LLM context before edits`
|
|
10606
11008
|
);
|
|
10607
11009
|
console.log(
|
|
10608
11010
|
` ${cyan3(withProject(verifyCommand, projectArg))} Run local health and drift checks`
|
|
10609
11011
|
);
|
|
10610
|
-
|
|
10611
|
-
console.log(
|
|
10612
|
-
` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose project-owned local law`
|
|
10613
|
-
);
|
|
10614
|
-
}
|
|
11012
|
+
console.log(` ${cyan3(withProject("decantr ci init", projectArg))} Wire the app into CI`);
|
|
10615
11013
|
return;
|
|
10616
11014
|
}
|
|
10617
11015
|
if (hasFootprint) {
|
|
@@ -10620,7 +11018,7 @@ async function cmdSetupWorkflow(args) {
|
|
|
10620
11018
|
` ${cyan3(withProject("decantr adopt --yes", projectArg))} Analyze, attach, and verify`
|
|
10621
11019
|
);
|
|
10622
11020
|
console.log(
|
|
10623
|
-
` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose local UI law`
|
|
11021
|
+
` ${cyan3(withProject("decantr codify --from-audit --style-bridge", projectArg))} Propose local UI law and style bridge`
|
|
10624
11022
|
);
|
|
10625
11023
|
console.log("");
|
|
10626
11024
|
console.log(`${BOLD9}Optional visual evidence after the app is running:${RESET16}`);
|
|
@@ -10679,7 +11077,7 @@ async function cmdAdoptWorkflow(args) {
|
|
|
10679
11077
|
const hydratePacks = flagBoolean(flags, "packs", true) && !flagBoolean(flags, "skip-packs") && !flagBoolean(flags, "offline") && process.env.DECANTR_OFFLINE !== "true";
|
|
10680
11078
|
const initCi = flagBoolean(flags, "ci") || flagBoolean(flags, "init-ci");
|
|
10681
11079
|
const assistantBridge = flagString(flags, "assistant-bridge");
|
|
10682
|
-
const hasEssence =
|
|
11080
|
+
const hasEssence = existsSync30(join32(projectRoot, "decantr.essence.json"));
|
|
10683
11081
|
const proposalFlag = flagBoolean(flags, "replace-essence") ? "--replace-essence" : flagBoolean(flags, "merge-proposal") || hasEssence ? "--merge-proposal" : "--accept-proposal";
|
|
10684
11082
|
const steps = [
|
|
10685
11083
|
"analyze current app and write .decantr/brownfield intelligence",
|
|
@@ -10727,7 +11125,7 @@ async function cmdAdoptWorkflow(args) {
|
|
|
10727
11125
|
if (hydratePacks) {
|
|
10728
11126
|
try {
|
|
10729
11127
|
const { bundle, contextDir } = await compileHostedExecutionPackBundle(
|
|
10730
|
-
|
|
11128
|
+
join32(projectRoot, "decantr.essence.json")
|
|
10731
11129
|
);
|
|
10732
11130
|
const written = writeHostedExecutionPackContextArtifacts(
|
|
10733
11131
|
contextDir,
|
|
@@ -10750,7 +11148,7 @@ async function cmdAdoptWorkflow(args) {
|
|
|
10750
11148
|
console.log(dim3("Skipping hosted pack hydration in offline mode."));
|
|
10751
11149
|
}
|
|
10752
11150
|
if (runVerify) {
|
|
10753
|
-
const { cmdHealth } = await import("./health-
|
|
11151
|
+
const { cmdHealth } = await import("./health-DBCUR6VQ.js");
|
|
10754
11152
|
await cmdHealth(projectRoot, {
|
|
10755
11153
|
browser: runBrowser,
|
|
10756
11154
|
browserBaseUrl: baseUrl,
|
|
@@ -10768,10 +11166,10 @@ async function cmdAdoptWorkflow(args) {
|
|
|
10768
11166
|
console.log("");
|
|
10769
11167
|
console.log(`${BOLD9}Brownfield operating loop:${RESET16}`);
|
|
10770
11168
|
console.log(
|
|
10771
|
-
` ${cyan3(withProject("decantr codify --from-audit", projectArg))}
|
|
11169
|
+
` ${cyan3(withProject("decantr codify --from-audit --style-bridge", projectArg))} Propose project-owned UI law and style bridge`
|
|
10772
11170
|
);
|
|
10773
11171
|
console.log(
|
|
10774
|
-
` ${cyan3(withProject("decantr codify --accept", projectArg))} Accept reviewed local patterns and
|
|
11172
|
+
` ${cyan3(withProject("decantr codify --accept", projectArg))} Accept reviewed local patterns, rules, and bridge`
|
|
10775
11173
|
);
|
|
10776
11174
|
console.log(
|
|
10777
11175
|
` ${cyan3(withProject('decantr task <route> "<change>"', projectArg))} Give your LLM route-specific context before edits`
|
|
@@ -10821,7 +11219,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10821
11219
|
return;
|
|
10822
11220
|
}
|
|
10823
11221
|
if (workspaceMode) {
|
|
10824
|
-
const { cmdWorkspace } = await import("./workspace-
|
|
11222
|
+
const { cmdWorkspace } = await import("./workspace-BCA5RCHN.js");
|
|
10825
11223
|
await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
|
|
10826
11224
|
return;
|
|
10827
11225
|
}
|
|
@@ -10854,7 +11252,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10854
11252
|
}
|
|
10855
11253
|
let guardExitCode;
|
|
10856
11254
|
if (brownfield) {
|
|
10857
|
-
const { cmdHeal, collectCheckIssues } = await import("./heal-
|
|
11255
|
+
const { cmdHeal, collectCheckIssues } = await import("./heal-WMSAX4LU.js");
|
|
10858
11256
|
if (quietOutput) {
|
|
10859
11257
|
const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
|
|
10860
11258
|
guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
|
|
@@ -10864,7 +11262,7 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10864
11262
|
process.exitCode = void 0;
|
|
10865
11263
|
}
|
|
10866
11264
|
}
|
|
10867
|
-
const { cmdHealth, parseHealthArgs } = await import("./health-
|
|
11265
|
+
const { cmdHealth, parseHealthArgs } = await import("./health-DBCUR6VQ.js");
|
|
10868
11266
|
await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
|
|
10869
11267
|
if (localPatterns) {
|
|
10870
11268
|
const validation = validateLocalLaw(workspaceInfo.appRoot);
|
|
@@ -10914,14 +11312,22 @@ async function cmdVerifyWorkflow(args) {
|
|
|
10914
11312
|
}
|
|
10915
11313
|
}
|
|
10916
11314
|
}
|
|
11315
|
+
const styleBridge = createStyleBridgeTaskSummary(workspaceInfo.appRoot);
|
|
11316
|
+
if (!quietOutput && styleBridge.path) {
|
|
11317
|
+
console.log("");
|
|
11318
|
+
console.log(`${GREEN16}Style bridge found:${RESET16} ${styleBridge.path}`);
|
|
11319
|
+
console.log(
|
|
11320
|
+
`${DIM16}${styleBridge.mappingCount} mapping(s), ${styleBridge.stylingApproach ?? "unknown"} styling${styleBridge.themeModes.length > 0 ? `, themes: ${styleBridge.themeModes.join(", ")}` : ""}${RESET16}`
|
|
11321
|
+
);
|
|
11322
|
+
}
|
|
10917
11323
|
if (guardExitCode && guardExitCode !== 0 && (!process.exitCode || process.exitCode === 0)) {
|
|
10918
11324
|
process.exitCode = guardExitCode;
|
|
10919
11325
|
}
|
|
10920
11326
|
}
|
|
10921
11327
|
function readJsonIfPresent(path) {
|
|
10922
|
-
if (!
|
|
11328
|
+
if (!existsSync30(path)) return null;
|
|
10923
11329
|
try {
|
|
10924
|
-
return JSON.parse(
|
|
11330
|
+
return JSON.parse(readFileSync23(path, "utf-8"));
|
|
10925
11331
|
} catch {
|
|
10926
11332
|
return null;
|
|
10927
11333
|
}
|
|
@@ -10933,6 +11339,7 @@ function mentionsWord(text, term) {
|
|
|
10933
11339
|
function createTaskAuthoritySummary(input) {
|
|
10934
11340
|
const detected = detectProject(input.projectRoot);
|
|
10935
11341
|
const hasLocalLaw = input.hasLocalPatterns || input.hasLocalRules;
|
|
11342
|
+
const hasStyleBridge = input.hasStyleBridge || input.adoptionMode === "style-bridge";
|
|
10936
11343
|
let lane = "Brownfield contract-only";
|
|
10937
11344
|
let sourceAuthority = "Existing app is authoritative; Decantr supplies contract context.";
|
|
10938
11345
|
let styleAuthority = "Use the existing styling system.";
|
|
@@ -10945,11 +11352,11 @@ function createTaskAuthoritySummary(input) {
|
|
|
10945
11352
|
sourceAuthority = "Existing app remains authoritative except where Decantr CSS is explicitly adopted.";
|
|
10946
11353
|
styleAuthority = "Decantr CSS runtime is active where adopted.";
|
|
10947
11354
|
activeAuthorities.push("Decantr CSS runtime");
|
|
10948
|
-
} else if (input.workflowMode === "brownfield-attach" &&
|
|
11355
|
+
} else if (input.workflowMode === "brownfield-attach" && hasStyleBridge) {
|
|
10949
11356
|
lane = "Hybrid style bridge";
|
|
10950
11357
|
sourceAuthority = "Existing app remains authoritative; Decantr intent maps through the style bridge.";
|
|
10951
11358
|
styleAuthority = "Use bridge tokens/classes as a mapping layer onto the app styling system.";
|
|
10952
|
-
activeAuthorities.push("style bridge");
|
|
11359
|
+
activeAuthorities.push("accepted style bridge");
|
|
10953
11360
|
} else if (input.workflowMode === "brownfield-attach" && hasLocalLaw) {
|
|
10954
11361
|
lane = "Hybrid local law";
|
|
10955
11362
|
sourceAuthority = "Existing app plus accepted project-owned UI law are authoritative.";
|
|
@@ -11018,7 +11425,7 @@ async function cmdTaskWorkflow(args) {
|
|
|
11018
11425
|
}
|
|
11019
11426
|
const route = routeInput.startsWith("/") ? routeInput : `/${routeInput}`;
|
|
11020
11427
|
const taskSummary = positional.slice(1).join(" ").trim();
|
|
11021
|
-
const essencePath =
|
|
11428
|
+
const essencePath = join32(workspaceInfo.appRoot, "decantr.essence.json");
|
|
11022
11429
|
const essence = readJsonIfPresent(essencePath);
|
|
11023
11430
|
if (!essence) {
|
|
11024
11431
|
console.error(
|
|
@@ -11042,16 +11449,22 @@ async function cmdTaskWorkflow(args) {
|
|
|
11042
11449
|
}
|
|
11043
11450
|
const section = essence.blueprint.sections.find((entry) => entry.id === target.section);
|
|
11044
11451
|
const page = section?.pages.find((entry) => entry.id === target.page);
|
|
11045
|
-
const contextDir =
|
|
11046
|
-
const manifest = readJsonIfPresent(
|
|
11047
|
-
const projectJson = readJsonIfPresent(
|
|
11452
|
+
const contextDir = join32(workspaceInfo.appRoot, ".decantr", "context");
|
|
11453
|
+
const manifest = readJsonIfPresent(join32(contextDir, "pack-manifest.json"));
|
|
11454
|
+
const projectJson = readJsonIfPresent(join32(workspaceInfo.appRoot, ".decantr", "project.json"));
|
|
11048
11455
|
const pagePack = manifest?.pages?.find((entry) => entry.id === target.page);
|
|
11049
11456
|
const sectionPack = manifest?.sections?.find((entry) => entry.id === target.section);
|
|
11050
|
-
const visualManifest = readJsonIfPresent(
|
|
11457
|
+
const visualManifest = readJsonIfPresent(join32(workspaceInfo.appRoot, ".decantr", "evidence", "visual-manifest.json"));
|
|
11051
11458
|
const screenshot = visualManifest?.routes?.find((entry) => entry.route === route)?.screenshot;
|
|
11052
11459
|
const localPatternPackPath = localPatternsPath(workspaceInfo.appRoot);
|
|
11053
11460
|
const localRuleManifestPath = localRulesPath(workspaceInfo.appRoot);
|
|
11461
|
+
const acceptedStyleBridgePath = styleBridgePath(workspaceInfo.appRoot);
|
|
11054
11462
|
const localLaw = createLocalLawTaskSummary(workspaceInfo.appRoot);
|
|
11463
|
+
const styleBridge = createStyleBridgeTaskSummary(workspaceInfo.appRoot);
|
|
11464
|
+
const displayedStyleBridge = {
|
|
11465
|
+
...styleBridge,
|
|
11466
|
+
path: styleBridge.path ? displayProjectPath(workspaceInfo, styleBridge.path) : null
|
|
11467
|
+
};
|
|
11055
11468
|
const displayedLocalLaw = {
|
|
11056
11469
|
...localLaw,
|
|
11057
11470
|
patternsPath: localLaw.patternsPath ? displayProjectPath(workspaceInfo, localLaw.patternsPath) : null,
|
|
@@ -11064,10 +11477,11 @@ async function cmdTaskWorkflow(args) {
|
|
|
11064
11477
|
projectRoot: workspaceInfo.appRoot,
|
|
11065
11478
|
workflowMode: projectJson?.initialized?.workflowMode ?? null,
|
|
11066
11479
|
adoptionMode: projectJson?.initialized?.adoptionMode ?? null,
|
|
11067
|
-
hasLocalPatterns:
|
|
11068
|
-
hasLocalRules:
|
|
11480
|
+
hasLocalPatterns: existsSync30(localPatternPackPath),
|
|
11481
|
+
hasLocalRules: existsSync30(localRuleManifestPath),
|
|
11069
11482
|
hasPackManifest: Boolean(manifest),
|
|
11070
|
-
taskSummary
|
|
11483
|
+
taskSummary,
|
|
11484
|
+
hasStyleBridge: existsSync30(acceptedStyleBridgePath)
|
|
11071
11485
|
});
|
|
11072
11486
|
const context = {
|
|
11073
11487
|
route,
|
|
@@ -11077,17 +11491,19 @@ async function cmdTaskWorkflow(args) {
|
|
|
11077
11491
|
shell: page?.shell ?? section?.shell ?? null,
|
|
11078
11492
|
patterns: page?.layout?.map(extractPatternName) ?? [],
|
|
11079
11493
|
read: [
|
|
11080
|
-
pagePack ? displayProjectPath(workspaceInfo,
|
|
11081
|
-
sectionPack ? displayProjectPath(workspaceInfo,
|
|
11082
|
-
manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo,
|
|
11494
|
+
pagePack ? displayProjectPath(workspaceInfo, join32(".decantr/context", pagePack.markdown)) : null,
|
|
11495
|
+
sectionPack ? displayProjectPath(workspaceInfo, join32(".decantr/context", sectionPack.markdown)) : null,
|
|
11496
|
+
manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join32(".decantr/context", manifest.scaffold.markdown)) : null,
|
|
11083
11497
|
displayProjectPath(workspaceInfo, ".decantr/context/scaffold.md"),
|
|
11084
11498
|
displayProjectPath(workspaceInfo, "DECANTR.md"),
|
|
11085
|
-
|
|
11086
|
-
|
|
11499
|
+
existsSync30(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
|
|
11500
|
+
existsSync30(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null,
|
|
11501
|
+
existsSync30(acceptedStyleBridgePath) ? displayProjectPath(workspaceInfo, ".decantr/style-bridge.json") : null
|
|
11087
11502
|
].filter(Boolean),
|
|
11088
11503
|
screenshot: screenshot?.startsWith(".decantr/") ? displayProjectPath(workspaceInfo, screenshot) : screenshot ?? null,
|
|
11089
11504
|
authority,
|
|
11090
11505
|
localLaw: displayedLocalLaw,
|
|
11506
|
+
styleBridge: displayedStyleBridge,
|
|
11091
11507
|
changedFiles: currentChangedFiles,
|
|
11092
11508
|
changedRoutes,
|
|
11093
11509
|
verifyCommand: withProject("decantr verify --brownfield --local-patterns", projectArg)
|
|
@@ -11144,6 +11560,20 @@ async function cmdTaskWorkflow(args) {
|
|
|
11144
11560
|
` ${YELLOW12}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
|
|
11145
11561
|
);
|
|
11146
11562
|
}
|
|
11563
|
+
if (context.styleBridge.path) {
|
|
11564
|
+
console.log("");
|
|
11565
|
+
console.log(`${BOLD9}Project-owned style bridge:${RESET16}`);
|
|
11566
|
+
console.log(
|
|
11567
|
+
` Bridge: ${cyan3(context.styleBridge.path)} (${context.styleBridge.mappingCount} mappings, ${context.styleBridge.stylingApproach ?? "unknown"} styling)`
|
|
11568
|
+
);
|
|
11569
|
+
if (context.styleBridge.themeModes.length > 0) {
|
|
11570
|
+
console.log(` Theme modes: ${context.styleBridge.themeModes.join(", ")}`);
|
|
11571
|
+
}
|
|
11572
|
+
for (const mapping of context.styleBridge.mappings.slice(0, 4)) {
|
|
11573
|
+
const hints = [...mapping.tokenHints, ...mapping.classHints].slice(0, 4).join(", ");
|
|
11574
|
+
console.log(` ${mapping.id}: ${mapping.label}${hints ? ` \u2014 ${hints}` : ""}`);
|
|
11575
|
+
}
|
|
11576
|
+
}
|
|
11147
11577
|
if (context.changedFiles.length > 0) {
|
|
11148
11578
|
console.log("");
|
|
11149
11579
|
console.log(`${BOLD9}Changed-file context:${RESET16}`);
|
|
@@ -11169,7 +11599,14 @@ async function cmdCodifyWorkflow(args) {
|
|
|
11169
11599
|
const projectArg = flagString(flags, "project");
|
|
11170
11600
|
if (!ensureAllowedFlags(
|
|
11171
11601
|
flags,
|
|
11172
|
-
[
|
|
11602
|
+
[
|
|
11603
|
+
"project",
|
|
11604
|
+
"from-audit",
|
|
11605
|
+
"discover-local-patterns",
|
|
11606
|
+
"codify-local-patterns",
|
|
11607
|
+
"style-bridge",
|
|
11608
|
+
"accept"
|
|
11609
|
+
],
|
|
11173
11610
|
"codify"
|
|
11174
11611
|
)) {
|
|
11175
11612
|
return;
|
|
@@ -11177,25 +11614,29 @@ async function cmdCodifyWorkflow(args) {
|
|
|
11177
11614
|
const workspaceInfo = resolveWorkflowProject(flags, "codify");
|
|
11178
11615
|
if (!workspaceInfo) return;
|
|
11179
11616
|
if (flagBoolean(flags, "accept")) {
|
|
11180
|
-
if (!
|
|
11617
|
+
if (!existsSync30(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync30(localRulesProposalPath(workspaceInfo.appRoot)) && !existsSync30(styleBridgeProposalPath(workspaceInfo.appRoot))) {
|
|
11181
11618
|
console.error(
|
|
11182
11619
|
error2(
|
|
11183
|
-
"No
|
|
11620
|
+
"No codify proposal found. Run `decantr codify --from-audit`, `decantr codify --style-bridge`, or `decantr codify` first."
|
|
11184
11621
|
)
|
|
11185
11622
|
);
|
|
11186
11623
|
process.exitCode = 1;
|
|
11187
11624
|
return;
|
|
11188
11625
|
}
|
|
11189
|
-
const
|
|
11190
|
-
|
|
11191
|
-
|
|
11626
|
+
const result = acceptBrownfieldLocalLaw(workspaceInfo.appRoot);
|
|
11627
|
+
const bridgeAcceptedPath = acceptStyleBridge(workspaceInfo.appRoot);
|
|
11628
|
+
if (result.patternAcceptedPath) {
|
|
11629
|
+
console.log(success3(`Accepted local pattern pack: ${result.patternAcceptedPath}`));
|
|
11630
|
+
}
|
|
11631
|
+
if (result.rulesAcceptedPath) {
|
|
11632
|
+
console.log(success3(`Accepted local rule manifest: ${result.rulesAcceptedPath}`));
|
|
11192
11633
|
}
|
|
11193
|
-
if (
|
|
11194
|
-
console.log(success3(`Accepted
|
|
11634
|
+
if (bridgeAcceptedPath) {
|
|
11635
|
+
console.log(success3(`Accepted style bridge: ${bridgeAcceptedPath}`));
|
|
11195
11636
|
}
|
|
11196
11637
|
console.log(
|
|
11197
11638
|
dim3(
|
|
11198
|
-
"Hybrid local law is now active: Decantr will treat accepted local patterns and rules as project-owned authority in task and verify flows."
|
|
11639
|
+
bridgeAcceptedPath ? "Hybrid style bridge is now active: Decantr will map design intent through accepted project tokens/classes in task, doctor, suggest, and CI flows." : "Hybrid local law is now active: Decantr will treat accepted local patterns and rules as project-owned authority in task and verify flows."
|
|
11199
11640
|
)
|
|
11200
11641
|
);
|
|
11201
11642
|
console.log(
|
|
@@ -11207,19 +11648,42 @@ async function cmdCodifyWorkflow(args) {
|
|
|
11207
11648
|
}
|
|
11208
11649
|
const detected = detectProject(workspaceInfo.appRoot);
|
|
11209
11650
|
const essence = readJsonIfPresent(
|
|
11210
|
-
|
|
11651
|
+
join32(workspaceInfo.appRoot, "decantr.essence.json")
|
|
11211
11652
|
);
|
|
11212
11653
|
const fromAudit = flagBoolean(flags, "from-audit") || flagBoolean(flags, "discover-local-patterns") || flagBoolean(flags, "codify-local-patterns");
|
|
11213
|
-
const
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11654
|
+
const wantsStyleBridge = flagBoolean(flags, "style-bridge");
|
|
11655
|
+
const wantsLocalLaw = !wantsStyleBridge || fromAudit;
|
|
11656
|
+
let localResult = null;
|
|
11657
|
+
if (wantsLocalLaw) {
|
|
11658
|
+
const proposal = createBrownfieldCodifyProposal({
|
|
11659
|
+
projectRoot: workspaceInfo.appRoot,
|
|
11660
|
+
detected,
|
|
11661
|
+
essence,
|
|
11662
|
+
fromAudit
|
|
11663
|
+
});
|
|
11664
|
+
localResult = writeBrownfieldCodifyProposal(workspaceInfo.appRoot, proposal);
|
|
11665
|
+
}
|
|
11666
|
+
let styleBridgeResult = null;
|
|
11667
|
+
if (wantsStyleBridge) {
|
|
11668
|
+
const styling = scanStyling(workspaceInfo.appRoot);
|
|
11669
|
+
styleBridgeResult = writeStyleBridgeProposal(
|
|
11670
|
+
workspaceInfo.appRoot,
|
|
11671
|
+
createStyleBridgeProposal({
|
|
11672
|
+
projectRoot: workspaceInfo.appRoot,
|
|
11673
|
+
detected,
|
|
11674
|
+
essence,
|
|
11675
|
+
styling
|
|
11676
|
+
})
|
|
11677
|
+
);
|
|
11678
|
+
}
|
|
11679
|
+
if (localResult) {
|
|
11680
|
+
console.log(success3(`Wrote local pattern proposal: ${localResult.patternPath}`));
|
|
11681
|
+
console.log(success3(`Wrote local rule proposal: ${localResult.rulesPath}`));
|
|
11682
|
+
}
|
|
11683
|
+
if (styleBridgeResult) {
|
|
11684
|
+
console.log(success3(`Wrote style bridge proposal: ${styleBridgeResult}`));
|
|
11685
|
+
}
|
|
11686
|
+
if (fromAudit && localResult) {
|
|
11223
11687
|
console.log(
|
|
11224
11688
|
dim3(
|
|
11225
11689
|
"Proposal includes source-derived component candidates, starter mechanical rules, and Hybrid authority guidance."
|
|
@@ -11228,7 +11692,7 @@ async function cmdCodifyWorkflow(args) {
|
|
|
11228
11692
|
}
|
|
11229
11693
|
console.log(
|
|
11230
11694
|
dim3(
|
|
11231
|
-
`Review
|
|
11695
|
+
`Review the proposal files, add real component paths/token/class recipes, map hosted pattern ideas into project-owned law, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
|
|
11232
11696
|
)
|
|
11233
11697
|
);
|
|
11234
11698
|
}
|
|
@@ -11283,7 +11747,7 @@ ${BOLD9}Usage:${RESET16}
|
|
|
11283
11747
|
decantr verify [--project <path>] [--brownfield] [--local-patterns] [health options]
|
|
11284
11748
|
decantr ci [--project <path>] [--workspace] [--fail-on error|warn|none]
|
|
11285
11749
|
decantr doctor [--project <path>] [--workspace] [--json]
|
|
11286
|
-
decantr codify [--from-audit] [--accept] [--project <path>]
|
|
11750
|
+
decantr codify [--from-audit] [--style-bridge] [--accept] [--project <path>]
|
|
11287
11751
|
decantr studio [--port 4319] [--host 127.0.0.1] [--report decantr-health.json] [--workspace]
|
|
11288
11752
|
|
|
11289
11753
|
${BOLD9}Advanced primitives:${RESET16}
|
|
@@ -11703,15 +12167,17 @@ ${BOLD9}Examples:${RESET16}
|
|
|
11703
12167
|
}
|
|
11704
12168
|
function cmdCodifyHelp() {
|
|
11705
12169
|
console.log(`
|
|
11706
|
-
${BOLD9}decantr codify${RESET16} \u2014 Propose or accept project-owned Brownfield UI
|
|
12170
|
+
${BOLD9}decantr codify${RESET16} \u2014 Propose or accept project-owned Brownfield UI law and style bridges
|
|
11707
12171
|
|
|
11708
12172
|
${BOLD9}Usage:${RESET16}
|
|
11709
|
-
decantr codify [--from-audit] [--project <path>]
|
|
12173
|
+
decantr codify [--from-audit] [--style-bridge] [--project <path>]
|
|
11710
12174
|
decantr codify --accept [--project <path>]
|
|
11711
12175
|
|
|
11712
12176
|
${BOLD9}Examples:${RESET16}
|
|
11713
12177
|
decantr codify
|
|
11714
12178
|
decantr codify --from-audit
|
|
12179
|
+
decantr codify --style-bridge
|
|
12180
|
+
decantr codify --from-audit --style-bridge
|
|
11715
12181
|
decantr codify --accept
|
|
11716
12182
|
decantr verify --brownfield --local-patterns
|
|
11717
12183
|
`);
|
|
@@ -11794,10 +12260,10 @@ async function main() {
|
|
|
11794
12260
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
11795
12261
|
try {
|
|
11796
12262
|
const here = dirname6(fileURLToPath3(import.meta.url));
|
|
11797
|
-
const candidates = [
|
|
12263
|
+
const candidates = [join32(here, "..", "package.json"), join32(here, "..", "..", "package.json")];
|
|
11798
12264
|
for (const candidate of candidates) {
|
|
11799
|
-
if (
|
|
11800
|
-
const pkg = JSON.parse(
|
|
12265
|
+
if (existsSync30(candidate)) {
|
|
12266
|
+
const pkg = JSON.parse(readFileSync23(candidate, "utf-8"));
|
|
11801
12267
|
if (pkg.version) {
|
|
11802
12268
|
console.log(pkg.version);
|
|
11803
12269
|
return;
|
|
@@ -11950,7 +12416,7 @@ async function main() {
|
|
|
11950
12416
|
`${YELLOW12}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
|
|
11951
12417
|
);
|
|
11952
12418
|
}
|
|
11953
|
-
const { cmdHeal } = await import("./heal-
|
|
12419
|
+
const { cmdHeal } = await import("./heal-WMSAX4LU.js");
|
|
11954
12420
|
const { flags } = parseLooseArgs(args);
|
|
11955
12421
|
const workspaceInfo = resolveWorkflowProject(flags, "check");
|
|
11956
12422
|
if (!workspaceInfo) break;
|
|
@@ -11975,7 +12441,7 @@ async function main() {
|
|
|
11975
12441
|
const { flags } = parseLooseArgs(args);
|
|
11976
12442
|
const workspaceInfo = resolveWorkflowProject(flags, "health");
|
|
11977
12443
|
if (!workspaceInfo) break;
|
|
11978
|
-
const { cmdHealth, parseHealthArgs } = await import("./health-
|
|
12444
|
+
const { cmdHealth, parseHealthArgs } = await import("./health-DBCUR6VQ.js");
|
|
11979
12445
|
await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
|
|
11980
12446
|
} catch (e) {
|
|
11981
12447
|
console.error(error2(e.message));
|
|
@@ -12003,7 +12469,7 @@ async function main() {
|
|
|
12003
12469
|
cmdStudioHelp();
|
|
12004
12470
|
break;
|
|
12005
12471
|
}
|
|
12006
|
-
const { cmdStudio, parseStudioArgs } = await import("./studio-
|
|
12472
|
+
const { cmdStudio, parseStudioArgs } = await import("./studio-L6JJQYCS.js");
|
|
12007
12473
|
await cmdStudio(process.cwd(), parseStudioArgs(args));
|
|
12008
12474
|
} catch (e) {
|
|
12009
12475
|
console.error(error2(e.message));
|
|
@@ -12017,7 +12483,7 @@ async function main() {
|
|
|
12017
12483
|
cmdWorkspaceHelp();
|
|
12018
12484
|
break;
|
|
12019
12485
|
}
|
|
12020
|
-
const { cmdWorkspace } = await import("./workspace-
|
|
12486
|
+
const { cmdWorkspace } = await import("./workspace-BCA5RCHN.js");
|
|
12021
12487
|
await cmdWorkspace(process.cwd(), args);
|
|
12022
12488
|
} catch (e) {
|
|
12023
12489
|
console.error(error2(e.message));
|
|
@@ -12336,7 +12802,7 @@ async function main() {
|
|
|
12336
12802
|
break;
|
|
12337
12803
|
}
|
|
12338
12804
|
if (packType === "page" && route && !id) {
|
|
12339
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
12805
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
|
|
12340
12806
|
id = resolvePagePackIdForRoute(resolvedPath, route);
|
|
12341
12807
|
}
|
|
12342
12808
|
await printHostedSelectedExecutionPack(
|