@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.
@@ -22,14 +22,14 @@ import {
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
24
  shouldFailWorkspaceHealth
25
- } from "./chunk-NUNUW5IS.js";
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-5WPRTVNA.js";
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-4SZ4SEKT.js";
49
+ } from "./chunk-CAKQWTZS.js";
50
50
 
51
51
  // src/index.ts
52
- import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync9, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "fs";
53
- import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute3, join as join31, relative as relative7, resolve as resolve4 } from "path";
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 existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
3237
- import { dirname as dirname3, join as join16, relative as relative4, resolve } from "path";
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 = wantsButton && buttonSignal.test(value) || wantsSurface && surfaceSignal.test(value) || !wantsButton && !wantsSurface && (buttonSignal.test(value) || surfaceSignal.test(value));
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 (!existsSync14(path)) return null;
4046
+ if (!existsSync15(path)) return null;
3760
4047
  try {
3761
- return JSON.parse(readFileSync12(path, "utf-8"));
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(join16(root, "package.json"));
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 (existsSync14(join16(root, "pnpm-lock.yaml"))) return "pnpm";
3811
- if (existsSync14(join16(root, "package-lock.json"))) return "npm";
3812
- if (existsSync14(join16(root, "yarn.lock"))) return "yarn";
3813
- if (existsSync14(join16(root, "bun.lock")) || existsSync14(join16(root, "bun.lockb"))) return "bun";
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(join16(root, "package.json"));
4104
+ const pkg = readJson(join17(root, "package.json"));
3818
4105
  return Boolean(
3819
- existsSync14(join16(root, "pnpm-workspace.yaml")) || existsSync14(join16(root, "turbo.json")) || existsSync14(join16(root, "nx.json")) || pkg?.workspaces
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(join16(root, "package.json"));
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
- mkdirSync9(dirname3(absolute), { recursive: true });
3874
- writeFileSync10(absolute, content, "utf-8");
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 projectCiStatus(health, localLaw) {
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) return "warning";
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 && !existsSync14(workspaceInfo.appRoot)) {
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 (existsSync14(absolute2) && !options.force) {
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 (existsSync14(absolute) && !options.force) {
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 && !existsSync14(workspaceInfo.appRoot)) {
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(`${formatProjectHealthText(health)}${formatLocalLawText(localLaw, health)}`);
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 existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
4236
- import { join as join17 } from "path";
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 = join17(projectRoot, ".decantr", "custom", plural);
4433
- const filePath = join17(customDir, `${name}.json`);
4434
- if (existsSync15(filePath)) {
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
- mkdirSync10(customDir, { recursive: true });
4794
+ mkdirSync11(customDir, { recursive: true });
4440
4795
  const skeleton = getSkeleton(contentType, name, humanizeId(name));
4441
- writeFileSync11(filePath, JSON.stringify(skeleton, null, 2));
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 existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
4448
- import { dirname as dirname4, join as join18, relative as relative5 } from "path";
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 (!existsSync16(path)) return null;
4815
+ if (!existsSync17(path)) return null;
4461
4816
  try {
4462
- return JSON.parse(readFileSync13(path, "utf-8"));
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(join18(projectRoot, ".decantr", "project.json"));
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 = join18(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4473
- const srcPackagePath = join18(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
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(join18(dir, "package.json"));
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 (existsSync16(join18(root, "pnpm-lock.yaml"))) return "pnpm";
4487
- if (existsSync16(join18(root, "package-lock.json"))) return "npm";
4488
- if (existsSync16(join18(root, "yarn.lock"))) return "yarn";
4489
- if (existsSync16(join18(root, "bun.lock")) || existsSync16(join18(root, "bun.lockb"))) return "bun";
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
- existsSync16(join18(root, "pnpm-workspace.yaml")) || existsSync16(join18(root, "turbo.json")) || existsSync16(join18(root, "nx.json")) || pkg?.workspaces
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 = join18(dir, name);
4523
- if (existsSync16(path)) return name;
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 (existsSync16(join18(workspaceRoot, candidate))) found.add(candidate);
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 (existsSync16(join18(root, ".storybook"))) found.add(`${label}:.storybook`);
4557
- if (existsSync16(join18(root, "components", "ui"))) found.add(`${label}:components/ui`);
4558
- if (existsSync16(join18(root, "src", "components", "ui"))) found.add(`${label}:src/components/ui`);
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 = join18(root, ".github", "workflows");
4571
- if (existsSync16(workflows)) {
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 = join18(workflows, entry.name);
4575
- const text = readFileSync13(path, "utf-8");
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 = join18(root, candidate);
4581
- if (existsSync16(path) && readFileSync13(path, "utf-8").includes("decantr")) {
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" : input.adoptionMode === "style-bridge" ? "Style bridge maps Decantr intent into the app styling system" : "Existing app styling system remains primary",
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 (input.adoptionMode === "style-bridge") {
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: ["existing source", "Essence V4 contract", "style bridge"],
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 && !existsSync16(appRoot));
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(join18(appRoot, ".decantr", "project.json"));
4717
- const essence = readJson2(join18(appRoot, "decantr.essence.json"));
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 = join18(appRoot, ".decantr", "context");
4720
- const packManifestPresent = existsSync16(join18(contextDir, "pack-manifest.json"));
4721
- const reviewPackPresent = existsSync16(join18(contextDir, "review-pack.json"));
4722
- const artifactReadmePresent = existsSync16(join18(appRoot, ARTIFACT_README_PATH));
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 = existsSync16(localPatternsPath(appRoot));
4734
- const localRulesPresent = existsSync16(localRulesPath(appRoot));
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(join18(workspaceRoot, project.path)).map(
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 = join18(workspaceRoot, projectPath2, ".decantr", "context");
4742
- return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "pack-manifest.json"));
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 = join18(workspaceRoot, projectPath2, ".decantr", "context");
4746
- return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "review-pack.json"));
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 && (!existsSync16(contextDir) || !packManifestPresent)) {
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) => existsSync16(join18(workspaceRoot, project.path, ".decantr", "context"))
4923
- ) : existsSync16(contextDir),
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: existsSync16(join18(appRoot, ".decantr", "evidence", "visual-manifest.json"))
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 existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
5041
- import { dirname as dirname5, isAbsolute, join as join19 } from "path";
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 = join19(projectRoot, ".decantr", "project.json");
5048
- if (!existsSync17(projectJsonPath)) return null;
5429
+ const projectJsonPath = join20(projectRoot, ".decantr", "project.json");
5430
+ if (!existsSync18(projectJsonPath)) return null;
5049
5431
  try {
5050
- const parsed = JSON.parse(readFileSync14(projectJsonPath, "utf-8"));
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 : join19(projectRoot, 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 = join19(projectRoot, "decantr.essence.json");
5220
- const tokensPath = join19(projectRoot, "src", "styles", "tokens.css");
5221
- if (!existsSync17(essencePath)) {
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 (!existsSync17(tokensPath)) {
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 = readFileSync14(tokensPath, "utf-8");
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
- join19(projectRoot, "src", "styles", "shadcn-theme.css")
5627
+ join20(projectRoot, "src", "styles", "shadcn-theme.css")
5246
5628
  );
5247
- const jsonOut = join19(projectRoot, "components.json");
5629
+ const jsonOut = join20(projectRoot, "components.json");
5248
5630
  ensureDir(cssOut);
5249
- writeFileSync12(cssOut, generateShadcnCSS(tokens), "utf-8");
5250
- writeFileSync12(jsonOut, generateShadcnComponentsJSON(), "utf-8");
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
- join19(projectRoot, "tailwind.decantr.config.ts")
5642
+ join20(projectRoot, "tailwind.decantr.config.ts")
5261
5643
  );
5262
5644
  ensureDir(out);
5263
- writeFileSync12(out, generateTailwindConfig(tokens), "utf-8");
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
- join19(projectRoot, "decantr-tokens.css")
5654
+ join20(projectRoot, "decantr-tokens.css")
5273
5655
  );
5274
5656
  ensureDir(out);
5275
- writeFileSync12(out, generateCSSVars(tokens), "utf-8");
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
- join19(projectRoot, ".decantr", "design", "figma-tokens.json")
5666
+ join20(projectRoot, ".decantr", "design", "figma-tokens.json")
5285
5667
  );
5286
5668
  ensureDir(out);
5287
- writeFileSync12(out, generateFigmaTokens(tokens), "utf-8");
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 (!existsSync17(dir)) {
5297
- mkdirSync11(dir, { recursive: true });
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 existsSync18 } from "fs";
5684
+ import { existsSync as existsSync19 } from "fs";
5303
5685
  import * as fs from "fs/promises";
5304
- import { join as join20 } from "path";
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 = join20(projectRoot, "decantr.essence.json");
5529
- if (existsSync18(essencePath)) {
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: join20(projectRoot, ".decantr", "cache"),
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 = join20(projectRoot, ".decantr", "context");
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 = join20(projectRoot, "src", "styles", "treatments.css");
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 existsSync19, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "fs";
5874
- import { join as join21 } from "path";
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 (!existsSync19(essencePath)) {
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 = readFileSync15(essencePath, "utf-8");
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
- writeFileSync13(essencePath, JSON.stringify(v4, null, 2) + "\n");
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 = join21(projectRoot, "decantr.essence.json");
5955
- if (!existsSync19(essencePath)) {
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: join21(projectRoot, ".decantr", "cache")
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 existsSync21, mkdirSync as mkdirSync13 } from "fs";
5989
- import { join as join23, resolve as resolve3 } from "path";
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 existsSync20, mkdirSync as mkdirSync12 } from "fs";
5994
- import { join as join22, resolve as resolve2 } from "path";
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 (!existsSync20(source)) return false;
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 (!existsSync20(contentRoot)) return false;
6004
- const customRoot = join22(projectDir, ".decantr", "custom");
6005
- const cacheRoot = join22(projectDir, ".decantr", "cache", "@official");
6006
- mkdirSync12(customRoot, { recursive: true });
6007
- mkdirSync12(cacheRoot, { recursive: true });
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 = join22(contentRoot, type);
6011
- if (!existsSync20(sourceDir)) continue;
6012
- cpSync(sourceDir, join22(customRoot, type), { recursive: true });
6013
- cpSync(sourceDir, join22(cacheRoot, type), { recursive: true });
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 = join22(projectDir, ".decantr");
6020
- mkdirSync12(projectDecantrRoot, { recursive: true });
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
- join22(workspaceRoot, ".decantr", "cache"),
6027
- join22(projectDecantrRoot, "cache")
6408
+ join23(workspaceRoot, ".decantr", "cache"),
6409
+ join23(projectDecantrRoot, "cache")
6028
6410
  );
6029
6411
  const copiedCustom = copyIfExists(
6030
- join22(workspaceRoot, ".decantr", "custom"),
6031
- join22(projectDecantrRoot, "custom")
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 = existsSync21(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync21(process.argv[1]) ? process.argv[1] : null;
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 (existsSync21(projectDir)) {
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
- mkdirSync13(projectDir, { recursive: true });
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 (existsSync21(join23(process.cwd(), "pnpm-lock.yaml")) || existsSync21(join23(process.cwd(), "pnpm-workspace.yaml"))) {
6667
+ if (existsSync22(join24(process.cwd(), "pnpm-lock.yaml")) || existsSync22(join24(process.cwd(), "pnpm-workspace.yaml"))) {
6286
6668
  return "pnpm";
6287
6669
  }
6288
- if (existsSync21(join23(process.cwd(), "yarn.lock"))) {
6670
+ if (existsSync22(join24(process.cwd(), "yarn.lock"))) {
6289
6671
  return "yarn";
6290
6672
  }
6291
- if (existsSync21(join23(process.cwd(), "bun.lockb")) || existsSync21(join23(process.cwd(), "bun.lock"))) {
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 existsSync22, readFileSync as readFileSync16 } from "fs";
6299
- import { join as join24 } from "path";
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 = join24(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
6316
- if (!existsSync22(customPath)) {
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(readFileSync16(customPath, "utf-8"));
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 existsSync23, readdirSync as readdirSync7, readFileSync as readFileSync17, statSync as statSync6 } from "fs";
6364
- import { isAbsolute as isAbsolute2, join as join25, relative as relative6 } from "path";
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(readFileSync17(path)).digest("hex");
6754
+ return createHash("sha256").update(readFileSync18(path)).digest("hex");
6373
6755
  }
6374
6756
  function walkFiles(dir) {
6375
- if (!existsSync23(dir)) return [];
6757
+ if (!existsSync24(dir)) return [];
6376
6758
  const files = [];
6377
6759
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
6378
- const path = join25(dir, entry.name);
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
- join25(projectRoot, "DECANTR.md"),
6390
- ...walkFiles(join25(projectRoot, ".decantr", "context")),
6391
- ...["global.css", "tokens.css", "treatments.css", "decantr-bridge.css"].map((file) => join25(projectRoot, "src", "styles", file)).filter((path) => existsSync23(path))
6392
- ].filter((path) => existsSync23(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(join25(projectRoot, "decantr.essence.json")),
6416
- fileMtimeMs(join25(projectRoot, ".decantr", "project.json"))
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 = join25(projectRoot, ".decantr", "project.json");
6421
- if (!existsSync23(projectJsonPath)) return false;
6802
+ const projectJsonPath = join26(projectRoot, ".decantr", "project.json");
6803
+ if (!existsSync24(projectJsonPath)) return false;
6422
6804
  try {
6423
- const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
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 = join25(projectRoot, ".decantr", "context");
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 (!existsSync23(join25(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
6435
- if (!existsSync23(contextDir)) reasons.push(".decantr/context is missing.");
6436
- if (!existsSync23(join25(contextDir, "scaffold.md"))) {
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 && !existsSync23(join25(contextDir, "pack-manifest.json"))) {
6821
+ if (!packHydrationOptional && !existsSync24(join26(contextDir, "pack-manifest.json"))) {
6440
6822
  reasons.push(".decantr/context/pack-manifest.json is missing.");
6441
- } else if (existsSync23(join25(contextDir, "pack-manifest.json"))) {
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 = join25(summary.projectRoot, file);
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 = join25(projectRoot, "decantr.essence.json");
6530
- if (!existsSync23(essencePath)) {
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 = readFileSync17(essencePath, "utf-8");
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: join25(projectRoot, ".decantr", "cache"),
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 mkdirSync14, writeFileSync as writeFileSync14 } from "fs";
6595
- import { join as join26 } from "path";
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 = join26(projectRoot, ".decantr", "cache");
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 = join26(cacheDir, "@official", type);
6634
- mkdirSync14(typeDir, { recursive: true });
6635
- writeFileSync14(join26(typeDir, "index.json"), JSON.stringify(result, null, 2));
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
- writeFileSync14(join26(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
7024
+ writeFileSync15(join27(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
6643
7025
  itemCount++;
6644
7026
  } catch {
6645
- writeFileSync14(join26(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
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
- mkdirSync14(join26(cacheDir), { recursive: true });
6661
- writeFileSync14(join26(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
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 existsSync25, readFileSync as readFileSync18, rmSync as rmSync2, writeFileSync as writeFileSync15 } from "fs";
6679
- import { join as join27 } from "path";
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 = join27(projectRoot, "decantr.essence.json");
6688
- if (!existsSync25(essencePath)) {
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(readFileSync18(essencePath, "utf-8"));
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
- writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n");
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 = join27(projectRoot, ".decantr", "context", `${sectionId}.md`);
6784
- if (existsSync25(contextFile)) {
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: join27(projectRoot, ".decantr", "cache")
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: join27(projectRoot, ".decantr", "cache")
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: join27(projectRoot, ".decantr", "cache")
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 existsSync26, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
6884
- import { join as join28 } from "path";
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 = join28(projectRoot, ".decantr", "drift-log.json");
6894
- if (!existsSync26(driftLogPath)) {
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(readFileSync19(driftLogPath, "utf-8"));
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 = join28(projectRoot, ".decantr", "drift-log.json");
6950
- if (!existsSync26(driftLogPath)) {
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
- writeFileSync16(driftLogPath, "[]");
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(readFileSync19(driftLogPath, "utf-8"));
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
- writeFileSync16(driftLogPath, JSON.stringify(entries, null, 2));
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 existsSync27, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "fs";
7208
- import { join as join29 } from "path";
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 = join29(projectRoot, "decantr.essence.json");
7226
- if (!existsSync27(essencePath)) {
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(readFileSync20(essencePath, "utf-8"));
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: join29(projectRoot, ".decantr", "cache")
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
- writeFileSync17(essencePath, JSON.stringify(essence, null, 2) + "\n");
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 existsSync28, mkdirSync as mkdirSync15, readdirSync as readdirSync8, readFileSync as readFileSync21, rmSync as rmSync3, writeFileSync as writeFileSync18 } from "fs";
7608
- import { join as join30 } from "path";
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 = join30(projectRoot, ".decantr", "custom", "themes");
7669
- const themePath = join30(customThemesDir, `${id}.json`);
7670
- const howToPath = join30(customThemesDir, "how-to-theme.md");
7671
- mkdirSync15(customThemesDir, { recursive: true });
7672
- if (existsSync28(themePath)) {
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
- writeFileSync18(themePath, JSON.stringify(skeleton, null, 2));
7680
- if (!existsSync28(howToPath)) {
7681
- writeFileSync18(howToPath, getHowToThemeDoc());
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 = join30(projectRoot, ".decantr", "custom", "themes");
7690
- if (!existsSync28(customThemesDir)) {
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 = join30(customThemesDir, file);
8079
+ const filePath = join31(customThemesDir, file);
7698
8080
  try {
7699
- const data = JSON.parse(readFileSync21(filePath, "utf-8"));
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 = join30(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
7715
- if (!existsSync28(themePath)) {
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 (!existsSync28(sourcePath)) {
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(readFileSync21(sourcePath, "utf-8"));
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 = join30(projectRoot, ".decantr", "custom", "themes");
7757
- const destPath = join30(customThemesDir, `${id}.json`);
7758
- mkdirSync15(customThemesDir, { recursive: true });
7759
- const howToPath = join30(customThemesDir, "how-to-theme.md");
7760
- if (!existsSync28(howToPath)) {
7761
- writeFileSync18(howToPath, getHowToThemeDoc());
7762
- }
7763
- writeFileSync18(destPath, JSON.stringify(theme, null, 2));
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) : join31(process.cwd(), "dist");
8311
- const indexPath = join31(resolvedDistPath, "index.html");
8312
- if (!existsSync29(indexPath)) {
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 = readFileSync22(indexPath, "utf-8");
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 = join31(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
8320
- if (existsSync29(assetFilePath)) {
8321
- assets[assetPath] = readFileSync22(assetFilePath, "utf-8");
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 (!existsSync29(resolvedSourcePath)) {
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 = join31(absoluteDir, entry.name);
8353
- const relativePath = join31(relativeDir, entry.name).replace(/\\/g, "/");
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] = readFileSync22(absolutePath, "utf-8");
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) : join31(process.cwd(), "decantr.essence.json");
8554
- if (!existsSync29(resolvedPath)) {
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(readFileSync22(resolvedPath, "utf-8"));
8939
+ const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
8558
8940
  const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
8559
- const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
8941
+ const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
8560
8942
  return { resolvedPath, bundle, contextDir };
8561
8943
  }
8562
8944
  function writeHostedExecutionPackContextArtifacts(contextDir, bundle) {
8563
- mkdirSync16(contextDir, { recursive: true });
8945
+ mkdirSync17(contextDir, { recursive: true });
8564
8946
  return writeExecutionPackBundleArtifacts(contextDir, bundle);
8565
8947
  }
8566
8948
  function resolvePagePackIdForRoute(essencePath, route) {
8567
- if (!existsSync29(essencePath)) {
8949
+ if (!existsSync30(essencePath)) {
8568
8950
  throw new Error(`Essence file not found at ${essencePath}`);
8569
8951
  }
8570
- const essence = JSON.parse(readFileSync22(essencePath, "utf-8"));
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) : join31(process.cwd(), "decantr.essence.json");
8586
- if (!existsSync29(resolvedPath)) {
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(readFileSync22(resolvedPath, "utf-8"));
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 = join31(dirname6(resolvedPath), ".decantr", "context");
8604
- mkdirSync16(contextDir, { recursive: true });
8605
- writeFileSync19(
8606
- join31(contextDir, "pack-manifest.json"),
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
- writeFileSync19(join31(contextDir, markdownFile), selected.pack.renderedMarkdown);
8613
- writeFileSync19(join31(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
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) : join31(process.cwd(), "decantr.essence.json");
8639
- if (!existsSync29(resolvedPath)) {
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(readFileSync22(resolvedPath, "utf-8"));
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 = join31(dirname6(resolvedPath), ".decantr", "context");
8650
- mkdirSync16(contextDir, { recursive: true });
8651
- writeFileSync19(join31(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
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 = join31(projectRoot, ".decantr", "context");
8673
- const reviewPackPath = join31(contextDir, "review-pack.json");
8674
- const manifestPath = join31(contextDir, "pack-manifest.json");
8675
- if (existsSync29(reviewPackPath) && existsSync29(manifestPath)) {
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 = join31(projectRoot, "decantr.essence.json");
8679
- if (!existsSync29(essencePath)) {
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(readFileSync22(essencePath, "utf-8"));
9070
+ const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
8689
9071
  const bundle = await client.compileExecutionPacks(essence, { namespace });
8690
- mkdirSync16(contextDir, { recursive: true });
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 = join31(projectRoot, ".decantr", "context");
8699
- const reviewPackPath = join31(contextDir, "review-pack.json");
8700
- const manifestPath = join31(contextDir, "pack-manifest.json");
8701
- if (existsSync29(reviewPackPath) && existsSync29(manifestPath)) {
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 = join31(projectRoot, "decantr.essence.json");
8705
- if (!existsSync29(essencePath)) {
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(readFileSync22(essencePath, "utf-8"));
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
- mkdirSync16(contextDir, { recursive: true });
8719
- writeFileSync19(join31(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
8720
- writeFileSync19(
8721
- join31(contextDir, "review-pack.json"),
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 (!existsSync29(manifestPath)) {
8725
- writeFileSync19(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
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) : join31(process.cwd(), "decantr.essence.json");
8736
- const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join31(process.cwd(), "src", "styles", "treatments.css");
8737
- if (!existsSync29(resolvedSourcePath)) {
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 (!existsSync29(resolvedEssencePath)) {
9122
+ if (!existsSync30(resolvedEssencePath)) {
8741
9123
  throw new Error(`Essence file not found at ${resolvedEssencePath}`);
8742
9124
  }
8743
- const code = readFileSync22(resolvedSourcePath, "utf-8");
8744
- const essence = JSON.parse(readFileSync22(resolvedEssencePath, "utf-8"));
8745
- const treatmentsCss = existsSync29(resolvedTreatmentsPath) ? readFileSync22(resolvedTreatmentsPath, "utf-8") : void 0;
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) : join31(process.cwd(), "decantr.essence.json");
8770
- if (!existsSync29(resolvedEssencePath)) {
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(readFileSync22(resolvedEssencePath, "utf-8"));
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) : join31(process.cwd(), "dist") : "none"}`
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 : join31(projectRoot, file);
8895
- if (existsSync29(resolved)) {
8896
- pieces.push(readFileSync22(resolved, "utf-8"));
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 = join31(projectRoot, ".decantr", "analysis.json");
8901
- if (existsSync29(analysisPath)) {
9282
+ const analysisPath = join32(projectRoot, ".decantr", "analysis.json");
9283
+ if (existsSync30(analysisPath)) {
8902
9284
  try {
8903
- const analysis = JSON.parse(readFileSync22(analysisPath, "utf-8"));
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 = join31(projectRoot, routeEntry.file);
8907
- if (existsSync29(resolved)) {
8908
- pieces.push(readFileSync22(resolved, "utf-8"));
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: join31(projectRoot, ".decantr", "cache")
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: join31(process.cwd(), ".decantr", "cache")
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 || join31(process.cwd(), "decantr.essence.json");
9478
+ const essencePath = path || join32(process.cwd(), "decantr.essence.json");
9088
9479
  let raw;
9089
9480
  try {
9090
- raw = readFileSync22(essencePath, "utf-8");
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: join31(process.cwd(), ".decantr", "cache")
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 = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
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(readFileSync22(candidate, "utf-8"));
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 = join31(projectRoot, "decantr.essence.json");
9255
- if (!existsSync29(essencePath)) return null;
9256
- const backupPath = join31(
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
- writeFileSync19(backupPath, readFileSync22(essencePath, "utf-8"), "utf-8");
9651
+ writeFileSync20(backupPath, readFileSync23(essencePath, "utf-8"), "utf-8");
9261
9652
  return backupPath;
9262
9653
  }
9263
9654
  function writeBrownfieldProjectJson(input) {
9264
- const decantrDir = join31(input.projectRoot, ".decantr");
9265
- mkdirSync16(join31(decantrDir, "context"), { recursive: true });
9266
- mkdirSync16(join31(decantrDir, "cache"), { recursive: true });
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
- writeFileSync19(join31(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
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 = join31(input.projectRoot, "decantr.essence.json");
9324
- const hasEssence = existsSync29(essencePath);
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(readFileSync22(essencePath, "utf-8"));
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
- writeFileSync19(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
9766
+ writeFileSync20(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
9376
9767
  const registryClient = new RegistryClient({
9377
- cacheDir: join31(input.projectRoot, ".decantr", "cache"),
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: join31(projectRoot, ".decantr", "cache"),
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 (!existsSync29(join31(projectRoot, "package.json"))) {
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 = existsSync29(join31(projectRoot, ".decantr", "context", "scaffold-pack.md"));
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 = readFileSync22(result.essencePath, "utf-8");
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 = join31(projectRoot, "decantr.essence.json");
9995
- const projectJsonPath = join31(projectRoot, ".decantr", "project.json");
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 (!existsSync29(essencePath)) {
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(readFileSync22(essencePath, "utf-8"));
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 (existsSync29(projectJsonPath)) {
10442
+ if (existsSync30(projectJsonPath)) {
10052
10443
  try {
10053
- const projectJson = JSON.parse(readFileSync22(projectJsonPath, "utf-8"));
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 = join31(projectRoot, ".decantr", "cache");
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 = join31(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
10266
- if (!existsSync29(themePath)) {
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(readFileSync22(themePath, "utf-8"));
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 = join31(workspaceInfo.appRoot, projectPath);
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) => existsSync29(join31(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
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 && !existsSync29(workspaceInfo.appRoot)) {
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 = existsSync29(localPatternsPath(workspaceInfo.appRoot));
10601
- const hasLocalRules = existsSync29(localRulesPath(workspaceInfo.appRoot));
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
- if (!hasLocalPatterns || !hasLocalRules) {
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 = existsSync29(join31(projectRoot, "decantr.essence.json"));
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
- join31(projectRoot, "decantr.essence.json")
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-ADHNLMX3.js");
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))} Discover and propose project-owned UI law`
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 rules`
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-YYCRXJNB.js");
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-2UCSPRTK.js");
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-ADHNLMX3.js");
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 (!existsSync29(path)) return null;
11328
+ if (!existsSync30(path)) return null;
10923
11329
  try {
10924
- return JSON.parse(readFileSync22(path, "utf-8"));
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" && input.adoptionMode === "style-bridge") {
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 = join31(workspaceInfo.appRoot, "decantr.essence.json");
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 = join31(workspaceInfo.appRoot, ".decantr", "context");
11046
- const manifest = readJsonIfPresent(join31(contextDir, "pack-manifest.json"));
11047
- const projectJson = readJsonIfPresent(join31(workspaceInfo.appRoot, ".decantr", "project.json"));
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(join31(workspaceInfo.appRoot, ".decantr", "evidence", "visual-manifest.json"));
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: existsSync29(localPatternPackPath),
11068
- hasLocalRules: existsSync29(localRuleManifestPath),
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, join31(".decantr/context", pagePack.markdown)) : null,
11081
- sectionPack ? displayProjectPath(workspaceInfo, join31(".decantr/context", sectionPack.markdown)) : null,
11082
- manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join31(".decantr/context", manifest.scaffold.markdown)) : null,
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
- existsSync29(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
11086
- existsSync29(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null
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
- ["project", "from-audit", "discover-local-patterns", "codify-local-patterns", "accept"],
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 (!existsSync29(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync29(localRulesProposalPath(workspaceInfo.appRoot))) {
11617
+ if (!existsSync30(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync30(localRulesProposalPath(workspaceInfo.appRoot)) && !existsSync30(styleBridgeProposalPath(workspaceInfo.appRoot))) {
11181
11618
  console.error(
11182
11619
  error2(
11183
- "No local law proposal found. Run `decantr codify --from-audit` or `decantr codify` first."
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 result2 = acceptBrownfieldLocalLaw(workspaceInfo.appRoot);
11190
- if (result2.patternAcceptedPath) {
11191
- console.log(success3(`Accepted local pattern pack: ${result2.patternAcceptedPath}`));
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 (result2.rulesAcceptedPath) {
11194
- console.log(success3(`Accepted local rule manifest: ${result2.rulesAcceptedPath}`));
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
- join31(workspaceInfo.appRoot, "decantr.essence.json")
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 proposal = createBrownfieldCodifyProposal({
11214
- projectRoot: workspaceInfo.appRoot,
11215
- detected,
11216
- essence,
11217
- fromAudit
11218
- });
11219
- const result = writeBrownfieldCodifyProposal(workspaceInfo.appRoot, proposal);
11220
- console.log(success3(`Wrote local pattern proposal: ${result.patternPath}`));
11221
- console.log(success3(`Wrote local rule proposal: ${result.rulesPath}`));
11222
- if (fromAudit) {
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 both files, add real component paths/token recipes, map hosted pattern ideas into project-owned law, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
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 patterns and rules
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 = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
12263
+ const candidates = [join32(here, "..", "package.json"), join32(here, "..", "..", "package.json")];
11798
12264
  for (const candidate of candidates) {
11799
- if (existsSync29(candidate)) {
11800
- const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
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-2UCSPRTK.js");
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-ADHNLMX3.js");
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-GZFCCVSO.js");
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-YYCRXJNB.js");
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) : join31(process.cwd(), "decantr.essence.json");
12805
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
12340
12806
  id = resolvePagePackIdForRoute(resolvedPath, route);
12341
12807
  }
12342
12808
  await printHostedSelectedExecutionPack(