@decantr/cli 2.11.0 → 2.13.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.
@@ -14,7 +14,7 @@ import {
14
14
  scaffoldProject,
15
15
  syncRegistry,
16
16
  writeExecutionPackBundleArtifacts
17
- } from "./chunk-IQZCIMQJ.js";
17
+ } from "./chunk-SIDKK73N.js";
18
18
  import {
19
19
  createWorkspaceHealthReport,
20
20
  formatWorkspaceHealthMarkdown,
@@ -22,14 +22,14 @@ import {
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
24
  shouldFailWorkspaceHealth
25
- } from "./chunk-NUNUW5IS.js";
25
+ } from "./chunk-YBSBAJ3E.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-3A2DLR47.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-MNZKOZW7.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 {
@@ -68,7 +68,8 @@ import {
68
68
  } from "@decantr/registry";
69
69
  import {
70
70
  auditProject,
71
- critiqueFile as critiqueProjectFile
71
+ critiqueFile as critiqueProjectFile,
72
+ scanProject as scanProjectReadOnly
72
73
  } from "@decantr/verifier";
73
74
 
74
75
  // src/artifacts.ts
@@ -88,6 +89,7 @@ Commit these when they exist:
88
89
  - \`.decantr/project.json\` - workflow, adoption mode, detection, and initialization metadata.
89
90
  - \`.decantr/local-patterns.json\` - project-owned Brownfield UI patterns accepted by the team.
90
91
  - \`.decantr/rules.json\` - project-owned mechanical rules accepted by the team.
92
+ - \`.decantr/style-bridge.json\` - accepted Hybrid style bridge from Decantr intent to project tokens/classes.
91
93
 
92
94
  ## Generated Context
93
95
 
@@ -3233,8 +3235,8 @@ ${YELLOW2}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then
3233
3235
  }
3234
3236
 
3235
3237
  // 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";
3238
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "fs";
3239
+ import { dirname as dirname3, join as join17, relative as relative4, resolve } from "path";
3238
3240
 
3239
3241
  // src/local-law.ts
3240
3242
  import { execFileSync } from "child_process";
@@ -3326,6 +3328,22 @@ function createBrownfieldCodifyProposal(input) {
3326
3328
  componentPaths: evidence.buttonComponents,
3327
3329
  decide: "Define primary, secondary, tertiary, destructive, icon-only, disabled, and loading button variants from this app.",
3328
3330
  classHints: evidence.buttonClassHints,
3331
+ variants: evidence.buttonVariants,
3332
+ sourceEvidence: evidence.buttonSourceEvidence,
3333
+ confidence: confidenceForEvidence({
3334
+ componentCount: evidence.buttonComponents.length,
3335
+ classHintCount: evidence.buttonClassHints.length,
3336
+ variantCount: evidence.buttonVariants.length,
3337
+ sourceEvidenceCount: evidence.buttonSourceEvidence.length
3338
+ }),
3339
+ enforcement: {
3340
+ level: "warn",
3341
+ status: "proposal",
3342
+ notes: [
3343
+ "Treat as advisory until the team confirms variant names and wrapper paths.",
3344
+ "Raise related rules to error only after raw button usage can be fixed without churn."
3345
+ ]
3346
+ },
3329
3347
  evidence: evidence.buttonComponents.length ? evidence.buttonComponents : evidence.buttonClassHints.length ? evidence.buttonClassHints : [
3330
3348
  "No obvious Button wrapper found yet. Add the project-owned wrapper path before strict enforcement."
3331
3349
  ],
@@ -3339,6 +3357,22 @@ function createBrownfieldCodifyProposal(input) {
3339
3357
  componentPaths: evidence.cardComponents,
3340
3358
  decide: "Define the canonical card background, border, radius, shadow, padding, density, and hover treatment.",
3341
3359
  classHints: evidence.cardClassHints,
3360
+ variants: evidence.cardVariants,
3361
+ sourceEvidence: evidence.cardSourceEvidence,
3362
+ confidence: confidenceForEvidence({
3363
+ componentCount: evidence.cardComponents.length,
3364
+ classHintCount: evidence.cardClassHints.length,
3365
+ variantCount: evidence.cardVariants.length,
3366
+ sourceEvidenceCount: evidence.cardSourceEvidence.length
3367
+ }),
3368
+ enforcement: {
3369
+ level: "warn",
3370
+ status: "proposal",
3371
+ notes: [
3372
+ "Use this family to converge repeated surface recipes before enforcing card rules.",
3373
+ "Document route-specific card exceptions before asking CI to block them."
3374
+ ]
3375
+ },
3342
3376
  evidence: evidence.cardComponents.length ? evidence.cardComponents : [
3343
3377
  "No obvious Card wrapper found yet. Add the project-owned wrapper path or class recipe."
3344
3378
  ],
@@ -3351,6 +3385,24 @@ function createBrownfieldCodifyProposal(input) {
3351
3385
  appliesTo: ["routes", "layouts", "navigation shells", "scroll containers"],
3352
3386
  componentPaths: evidence.shellComponents,
3353
3387
  decide: "Define which layout owns max width, gutters, sticky chrome, responsive breakpoints, and scroll containers.",
3388
+ sourceEvidence: collectSourceEvidence(input.projectRoot, sourceFiles, [
3389
+ "layout",
3390
+ "shell",
3391
+ "nav",
3392
+ "sidebar",
3393
+ "container"
3394
+ ]),
3395
+ confidence: confidenceForEvidence({
3396
+ componentCount: evidence.shellComponents.length,
3397
+ sourceEvidenceCount: evidence.shellComponents.length
3398
+ }),
3399
+ enforcement: {
3400
+ level: "advisory",
3401
+ status: "proposal",
3402
+ notes: [
3403
+ "Layout ownership is usually reviewed by humans first because route shells can legitimately differ."
3404
+ ]
3405
+ },
3354
3406
  evidence: evidence.shellComponents.length ? evidence.shellComponents : ["Add root layout, shell, or app frame files that establish route chrome and spacing."],
3355
3407
  forbiddenAlternatives: [
3356
3408
  "Each page inventing independent max-width, padding, or sticky nav rules."
@@ -3363,6 +3415,20 @@ function createBrownfieldCodifyProposal(input) {
3363
3415
  appliesTo: ["inputs", "selects", "textareas", "validation messages", "form actions"],
3364
3416
  componentPaths: evidence.formComponents,
3365
3417
  decide: "Define input height, label placement, error copy, disabled state, required state, and focus treatment.",
3418
+ variants: evidence.formVariants,
3419
+ sourceEvidence: evidence.formSourceEvidence,
3420
+ confidence: confidenceForEvidence({
3421
+ componentCount: evidence.formComponents.length,
3422
+ variantCount: evidence.formVariants.length,
3423
+ sourceEvidenceCount: evidence.formSourceEvidence.length
3424
+ }),
3425
+ enforcement: {
3426
+ level: "warn",
3427
+ status: "proposal",
3428
+ notes: [
3429
+ "Start by mapping field wrappers, labels, error states, and disabled states from source."
3430
+ ]
3431
+ },
3366
3432
  evidence: evidence.formComponents.length ? evidence.formComponents : ["Add form field wrapper paths and validation examples."],
3367
3433
  forbiddenAlternatives: [
3368
3434
  "Unlabeled one-off inputs or validation states that do not match the app standard."
@@ -3375,6 +3441,20 @@ function createBrownfieldCodifyProposal(input) {
3375
3441
  appliesTo: ["theme toggles", "mode-specific classes", "brand variants", "tenant variants"],
3376
3442
  componentPaths: evidence.themeComponents,
3377
3443
  decide: "Document which theme variants exist, where they are toggled, and which tokens/classes are legal per variant.",
3444
+ variants: evidence.themeVariants,
3445
+ sourceEvidence: evidence.themeSourceEvidence,
3446
+ confidence: confidenceForEvidence({
3447
+ componentCount: evidence.themeComponents.length,
3448
+ variantCount: evidence.themeVariants.length,
3449
+ sourceEvidenceCount: evidence.themeSourceEvidence.length
3450
+ }),
3451
+ enforcement: {
3452
+ level: "advisory",
3453
+ status: "proposal",
3454
+ notes: [
3455
+ "Theme variant law should preserve the existing theme provider/tokens before adding any new mode."
3456
+ ]
3457
+ },
3378
3458
  evidence: evidence.themeComponents.length ? evidence.themeComponents : ["If the app has dark/light or brand variants, add the toggles/providers here."],
3379
3459
  forbiddenAlternatives: [
3380
3460
  "Component-local theme forks that bypass shared theme providers or tokens."
@@ -3466,6 +3546,107 @@ function writeBrownfieldCodifyProposal(projectRoot, proposal) {
3466
3546
  `, "utf-8");
3467
3547
  return { patternPath, rulesPath };
3468
3548
  }
3549
+ function writeHostedPatternMappingProposal(input) {
3550
+ const decantrDir = join15(input.projectRoot, ".decantr");
3551
+ mkdirSync8(decantrDir, { recursive: true });
3552
+ const existing = readJsonFile(localPatternsProposalPath(input.projectRoot)) ?? readJsonFile(localPatternsPath(input.projectRoot));
3553
+ const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
3554
+ const patternPack = {
3555
+ version: 2,
3556
+ generatedAt,
3557
+ status: "proposal",
3558
+ source: "decantr codify --map-pattern",
3559
+ purpose: existing?.purpose ?? "Project-owned Brownfield/Hybrid UI law. Review and edit before accepting; Decantr treats this as authoritative only after it is copied to .decantr/local-patterns.json.",
3560
+ hybrid: existing?.hybrid ?? {
3561
+ intent: "This local pattern pack maps Decantr concepts onto project-owned components, tokens, classes, and rules without replacing the app runtime.",
3562
+ authorityPrecedence: [
3563
+ "existing production source",
3564
+ "accepted local patterns and rules",
3565
+ "Decantr Essence V4 contract",
3566
+ "hosted registry patterns and execution packs as optional guidance"
3567
+ ],
3568
+ hostedPatternMapping: "Hosted registry patterns are advisory until mapped to project-owned component paths, token recipes, class recipes, and explicit exceptions."
3569
+ },
3570
+ patterns: Array.isArray(existing?.patterns) ? [...existing.patterns] : [],
3571
+ starterRules: Array.isArray(existing?.starterRules) ? existing.starterRules : [],
3572
+ nextSteps: Array.isArray(existing?.nextSteps) ? existing.nextSteps : [
3573
+ "Review this proposal with the team.",
3574
+ "Add project-owned component paths, token hints, class recipes, and exceptions.",
3575
+ "Run decantr codify --accept after review.",
3576
+ "Use decantr task <route> before LLM edits so local law appears in task context."
3577
+ ]
3578
+ };
3579
+ const slug = input.hostedPattern.slug.trim();
3580
+ const existingIds = new Set(
3581
+ (patternPack.patterns ?? []).map((pattern) => typeof pattern.id === "string" ? pattern.id : "").filter(Boolean)
3582
+ );
3583
+ const localPatternId = existingIds.has(slug) ? `${slug}-registry-map` : slug;
3584
+ const mappedPattern = {
3585
+ id: localPatternId,
3586
+ label: input.hostedPattern.name ? `${input.hostedPattern.name} registry mapping` : `${slug} registry mapping`,
3587
+ role: "Hosted registry guidance mapped into project-owned Hybrid law",
3588
+ appliesTo: [
3589
+ ...input.hostedPattern.components ?? [],
3590
+ ...input.hostedPattern.interactions ?? [],
3591
+ ...input.hostedPattern.tags ?? []
3592
+ ].slice(0, 24),
3593
+ componentPaths: [],
3594
+ tokenHints: [],
3595
+ classHints: [],
3596
+ decide: `Map hosted pattern "${slug}" into this app's existing components, tokens, classes, and exceptions before treating it as enforceable.`,
3597
+ hostedPatternRefs: [input.hostedPattern],
3598
+ confidence: {
3599
+ tier: "low",
3600
+ score: 0.25,
3601
+ rationale: [
3602
+ "A hosted registry pattern was selected intentionally.",
3603
+ "No project-owned component path or token recipe has been mapped yet."
3604
+ ]
3605
+ },
3606
+ enforcement: {
3607
+ level: "advisory",
3608
+ status: "needs-mapping",
3609
+ notes: [
3610
+ "This proposal does not change source files.",
3611
+ "Do not enforce this hosted pattern until project-owned implementation details are filled in.",
3612
+ "Use accepted local rules, ESLint, Biome, Storybook, or visual regression for deterministic blocking checks."
3613
+ ]
3614
+ },
3615
+ evidence: [
3616
+ `Hosted pattern ${input.hostedPattern.source}/${slug}${input.hostedPattern.description ? `: ${input.hostedPattern.description}` : ""}`,
3617
+ input.hostedPattern.visualBrief ? `Visual brief: ${input.hostedPattern.visualBrief}` : "Visual brief not provided by the hosted pattern."
3618
+ ],
3619
+ evidenceToCollect: [
3620
+ "Project-owned component path(s) that implement this pattern.",
3621
+ "Allowed token/class recipe(s) for this app.",
3622
+ "Variant names and states that are legal in this project.",
3623
+ "Explicit exceptions where this hosted pattern should not apply."
3624
+ ],
3625
+ forbiddenAlternatives: [
3626
+ "Replacing existing app components solely because a hosted pattern exists.",
3627
+ "Treating hosted registry guidance as enforceable without accepted local law."
3628
+ ]
3629
+ };
3630
+ const index = (patternPack.patterns ?? []).findIndex((pattern) => pattern.id === localPatternId);
3631
+ const replacedExisting = index >= 0;
3632
+ if (replacedExisting) {
3633
+ patternPack.patterns[index] = mappedPattern;
3634
+ } else {
3635
+ patternPack.patterns = [...patternPack.patterns ?? [], mappedPattern];
3636
+ }
3637
+ patternPack.nextSteps = [
3638
+ .../* @__PURE__ */ new Set([
3639
+ ...patternPack.nextSteps ?? [],
3640
+ "Fill the hosted mapping with project-owned component paths, token/class recipes, variants, and exceptions.",
3641
+ "Run decantr codify --accept only after the mapping reflects the existing app.",
3642
+ "Use decantr verify --brownfield --local-patterns after edits to keep mapped local law visible."
3643
+ ])
3644
+ ];
3645
+ const patternPath = localPatternsProposalPath(input.projectRoot);
3646
+ writeFileSync9(patternPath, `${JSON.stringify(patternPack, null, 2)}
3647
+ `, "utf-8");
3648
+ return { patternPath, localPatternId, replacedExisting };
3649
+ }
3469
3650
  function acceptBrownfieldLocalLaw(projectRoot) {
3470
3651
  const patternProposal = readJsonFile(localPatternsProposalPath(projectRoot));
3471
3652
  const ruleProposal = readJsonFile(localRulesProposalPath(projectRoot));
@@ -3508,11 +3689,17 @@ function validateLocalLaw(projectRoot) {
3508
3689
  const paths = Array.isArray(pattern.componentPaths) ? pattern.componentPaths : [];
3509
3690
  const evidence = Array.isArray(pattern.evidence) ? pattern.evidence : [];
3510
3691
  const todoEvidence = Array.isArray(pattern.evidenceToCollect) ? pattern.evidenceToCollect : [];
3692
+ const hostedRefs = Array.isArray(pattern.hostedPatternRefs) ? pattern.hostedPatternRefs : [];
3511
3693
  if (id && paths.length === 0 && evidence.length === 0 && todoEvidence.length > 0) {
3512
3694
  warnings.push(
3513
3695
  `Local pattern ${id} still reads like a TODO; add concrete component paths or evidence.`
3514
3696
  );
3515
3697
  }
3698
+ if (id && hostedRefs.length > 0 && paths.length === 0) {
3699
+ warnings.push(
3700
+ `Local pattern ${id} maps hosted registry guidance but has no project-owned component path yet.`
3701
+ );
3702
+ }
3516
3703
  }
3517
3704
  }
3518
3705
  if (ruleManifest && !Array.isArray(ruleManifest.rules)) {
@@ -3534,7 +3721,10 @@ function createLocalLawTaskSummary(projectRoot) {
3534
3721
  const patterns = (patternPack?.patterns ?? []).map((pattern) => ({
3535
3722
  id: typeof pattern.id === "string" ? pattern.id : "unknown",
3536
3723
  role: typeof pattern.role === "string" ? pattern.role : null,
3537
- componentPaths: Array.isArray(pattern.componentPaths) ? pattern.componentPaths.filter((entry) => typeof entry === "string") : []
3724
+ componentPaths: Array.isArray(pattern.componentPaths) ? pattern.componentPaths.filter((entry) => typeof entry === "string") : [],
3725
+ confidenceTier: typeof pattern.confidence === "object" && pattern.confidence !== null && typeof pattern.confidence.tier === "string" ? pattern.confidence.tier : null,
3726
+ enforcementLevel: typeof pattern.enforcement === "object" && pattern.enforcement !== null && typeof pattern.enforcement.level === "string" ? pattern.enforcement.level : null,
3727
+ hostedPatternRefs: Array.isArray(pattern.hostedPatternRefs) ? pattern.hostedPatternRefs.map((ref) => typeof ref?.slug === "string" ? ref.slug : null).filter((slug) => Boolean(slug)) : []
3538
3728
  }));
3539
3729
  const rules = (ruleManifest?.rules ?? []).map((rule) => ({
3540
3730
  id: rule.id,
@@ -3652,6 +3842,50 @@ function summarizeSourceEvidence(projectRoot, files) {
3652
3842
  formComponents: byName(["input", "field", "form", "select", "textarea"]),
3653
3843
  shellComponents,
3654
3844
  themeComponents,
3845
+ buttonVariants: detectVariants(projectRoot, files, {
3846
+ family: "button",
3847
+ terms: ["primary", "secondary", "tertiary", "ghost", "link", "destructive", "icon"]
3848
+ }),
3849
+ cardVariants: detectVariants(projectRoot, files, {
3850
+ family: "surface",
3851
+ terms: ["card", "panel", "surface", "tile", "elevated", "interactive", "glass"]
3852
+ }),
3853
+ formVariants: detectVariants(projectRoot, files, {
3854
+ family: "form",
3855
+ terms: ["error", "invalid", "disabled", "required", "success", "helper"]
3856
+ }),
3857
+ themeVariants: detectVariants(projectRoot, files, {
3858
+ family: "theme",
3859
+ terms: ["dark", "light", "brand", "tenant", "theme", "mode", "density"]
3860
+ }),
3861
+ buttonSourceEvidence: collectSourceEvidence(projectRoot, files, [
3862
+ "button",
3863
+ "primary",
3864
+ "secondary",
3865
+ "tertiary",
3866
+ "destructive"
3867
+ ]),
3868
+ cardSourceEvidence: collectSourceEvidence(projectRoot, files, [
3869
+ "card",
3870
+ "panel",
3871
+ "surface",
3872
+ "rounded",
3873
+ "shadow"
3874
+ ]),
3875
+ formSourceEvidence: collectSourceEvidence(projectRoot, files, [
3876
+ "input",
3877
+ "label",
3878
+ "error",
3879
+ "field",
3880
+ "select"
3881
+ ]),
3882
+ themeSourceEvidence: collectSourceEvidence(projectRoot, files, [
3883
+ "theme",
3884
+ "dark",
3885
+ "light",
3886
+ "brand",
3887
+ "tenant"
3888
+ ]),
3655
3889
  buttonClassHints: collectClassHints(projectRoot, files, [
3656
3890
  "button",
3657
3891
  "btn",
@@ -3665,6 +3899,70 @@ function summarizeSourceEvidence(projectRoot, files) {
3665
3899
  cardClassHints: collectClassHints(projectRoot, files, ["card", "panel", "surface", "tile"])
3666
3900
  };
3667
3901
  }
3902
+ function detectVariants(projectRoot, files, input) {
3903
+ const variants = /* @__PURE__ */ new Map();
3904
+ const termPattern = new RegExp(
3905
+ `\\b(${input.terms.map(escapeRegExp).join("|")})(?:[-_:][a-z0-9-]+)?\\b`,
3906
+ "gi"
3907
+ );
3908
+ for (const file of files) {
3909
+ if (!UI_TEMPLATE_EXTENSIONS.has(extname(file.absolute))) continue;
3910
+ const content = readFileSync11(join15(projectRoot, file.relative), "utf-8");
3911
+ for (const match of content.matchAll(termPattern)) {
3912
+ const raw = (match[0] ?? "").toLowerCase();
3913
+ const id = raw.replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
3914
+ if (!id || id.length < 3) continue;
3915
+ const position = lineColumnAt(content, match.index ?? 0);
3916
+ const line = lineAt(content, position.line).trim().slice(0, 160);
3917
+ const entry = variants.get(id) ?? { evidence: /* @__PURE__ */ new Set(), count: 0 };
3918
+ entry.count += 1;
3919
+ entry.evidence.add(`${file.relative}:${position.line} ${line}`);
3920
+ variants.set(id, entry);
3921
+ }
3922
+ }
3923
+ return [...variants.entries()].sort((a, b) => b[1].count - a[1].count || a[0].localeCompare(b[0])).slice(0, 8).map(([id, value]) => ({
3924
+ id,
3925
+ label: `${input.family} ${id}`,
3926
+ evidence: [...value.evidence].slice(0, 4),
3927
+ confidence: value.count >= 4 ? "high" : value.count >= 2 ? "medium" : "low"
3928
+ }));
3929
+ }
3930
+ function collectSourceEvidence(projectRoot, files, terms) {
3931
+ const results = [];
3932
+ const termPattern = new RegExp(terms.map(escapeRegExp).join("|"), "i");
3933
+ for (const file of files) {
3934
+ if (!UI_TEMPLATE_EXTENSIONS.has(extname(file.absolute))) continue;
3935
+ const content = readFileSync11(join15(projectRoot, file.relative), "utf-8");
3936
+ const lines = content.split(/\r?\n/);
3937
+ for (let index = 0; index < lines.length; index += 1) {
3938
+ const line = lines[index];
3939
+ if (!termPattern.test(line)) continue;
3940
+ const signals = terms.filter((term) => line.toLowerCase().includes(term.toLowerCase()));
3941
+ results.push({
3942
+ file: file.relative,
3943
+ line: index + 1,
3944
+ excerpt: line.trim().slice(0, 180),
3945
+ signals: signals.slice(0, 6)
3946
+ });
3947
+ if (results.length >= 16) return results;
3948
+ break;
3949
+ }
3950
+ }
3951
+ return results;
3952
+ }
3953
+ function confidenceForEvidence(input) {
3954
+ const score = Math.min(
3955
+ 1,
3956
+ input.componentCount * 0.28 + (input.classHintCount ?? 0) * 0.08 + (input.variantCount ?? 0) * 0.08 + (input.sourceEvidenceCount ?? 0) * 0.05
3957
+ );
3958
+ const tier = score >= 0.7 ? "high" : score >= 0.4 ? "medium" : "low";
3959
+ const rationale = [
3960
+ input.componentCount > 0 ? `${input.componentCount} likely component path(s) detected` : "no likely component wrapper detected yet",
3961
+ (input.classHintCount ?? 0) > 0 ? `${input.classHintCount} class recipe hint(s) detected` : "no strong class recipe hints detected yet",
3962
+ (input.variantCount ?? 0) > 0 ? `${input.variantCount} possible variant signal(s) detected` : "variant names still need team confirmation"
3963
+ ];
3964
+ return { tier, score: Number(score.toFixed(2)), rationale };
3965
+ }
3668
3966
  function collectClassHints(projectRoot, files, terms) {
3669
3967
  const hints = /* @__PURE__ */ new Map();
3670
3968
  const wantsButton = terms.some(
@@ -3677,10 +3975,25 @@ function collectClassHints(projectRoot, files, terms) {
3677
3975
  if (!UI_TEMPLATE_EXTENSIONS.has(extname(file.absolute))) continue;
3678
3976
  const content = readFileSync11(join15(projectRoot, file.relative), "utf-8");
3679
3977
  if (!terms.some((term) => content.toLowerCase().includes(term))) continue;
3978
+ if (wantsButton) {
3979
+ const openingTags = content.matchAll(
3980
+ /<([A-Za-z][\w.:/-]*)\b[^>]*\bclass(?:Name)?\s*=\s*["'`]([^"'`]+)["'`][^>]*>/g
3981
+ );
3982
+ for (const match of openingTags) {
3983
+ const tag = match[1];
3984
+ const value = match[2].trim();
3985
+ const tagLooksInteractive = /^(button|a|Link)$/i.test(tag) || /(^|\.)(Button|IconButton|LinkButton|Action)$/i.test(tag);
3986
+ const fileLooksInteractive = /button|action|link/i.test(basename2(file.relative));
3987
+ if (!tagLooksInteractive && !fileLooksInteractive) continue;
3988
+ if (!buttonSignal.test(value) && !fileLooksInteractive) continue;
3989
+ hints.set(value, (hints.get(value) ?? 0) + 1);
3990
+ }
3991
+ continue;
3992
+ }
3680
3993
  const matches = content.matchAll(/\bclass(?:Name)?\s*=\s*["'`]([^"'`]+)["'`]/g);
3681
3994
  for (const match of matches) {
3682
3995
  const value = match[1].trim();
3683
- const keep = wantsButton && buttonSignal.test(value) || wantsSurface && surfaceSignal.test(value) || !wantsButton && !wantsSurface && (buttonSignal.test(value) || surfaceSignal.test(value));
3996
+ const keep = wantsSurface && surfaceSignal.test(value) || !wantsButton && !wantsSurface && (buttonSignal.test(value) || surfaceSignal.test(value));
3684
3997
  if (!keep) continue;
3685
3998
  hints.set(value, (hints.get(value) ?? 0) + 1);
3686
3999
  }
@@ -3744,10 +4057,284 @@ function lineColumnAt(contents, index) {
3744
4057
  column: lines[lines.length - 1].length + 1
3745
4058
  };
3746
4059
  }
4060
+ function escapeRegExp(value) {
4061
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4062
+ }
3747
4063
  function lineAt(contents, line) {
3748
4064
  return contents.split(/\r?\n/)[line - 1] ?? "";
3749
4065
  }
3750
4066
 
4067
+ // src/style-bridge.ts
4068
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
4069
+ import { join as join16 } from "path";
4070
+ function styleBridgeProposalPath(projectRoot) {
4071
+ return join16(projectRoot, ".decantr", "style-bridge.proposal.json");
4072
+ }
4073
+ function styleBridgePath(projectRoot) {
4074
+ return join16(projectRoot, ".decantr", "style-bridge.json");
4075
+ }
4076
+ function readJsonFile2(path) {
4077
+ if (!existsSync14(path)) return null;
4078
+ try {
4079
+ return JSON.parse(readFileSync12(path, "utf-8"));
4080
+ } catch {
4081
+ return null;
4082
+ }
4083
+ }
4084
+ function writeJsonFile(path, value) {
4085
+ writeFileSync10(path, `${JSON.stringify(value, null, 2)}
4086
+ `, "utf-8");
4087
+ }
4088
+ function readStyleBridge(projectRoot) {
4089
+ return readJsonFile2(styleBridgePath(projectRoot));
4090
+ }
4091
+ function readStyleBridgeProposal(projectRoot) {
4092
+ return readJsonFile2(styleBridgeProposalPath(projectRoot));
4093
+ }
4094
+ function stringArray(value) {
4095
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
4096
+ }
4097
+ function readThemeInventory(projectRoot) {
4098
+ const inventory = readJsonFile2(join16(projectRoot, ".decantr", "theme-inventory.json"));
4099
+ return {
4100
+ modes: stringArray(inventory?.modes),
4101
+ variantIds: Array.isArray(inventory?.variants) ? inventory.variants.map((variant) => variant.id).filter((id) => typeof id === "string") : [],
4102
+ darkModeDetected: typeof inventory?.darkModeDetected === "boolean" ? inventory.darkModeDetected : null
4103
+ };
4104
+ }
4105
+ function tokenHints(styling, terms) {
4106
+ return styling.cssVariables.filter((name) => terms.test(name)).slice(0, 12);
4107
+ }
4108
+ function readProjectPatternPack(projectRoot) {
4109
+ return readLocalPatternPack(projectRoot) ?? readJsonFile2(
4110
+ join16(projectRoot, ".decantr", "local-patterns.proposal.json")
4111
+ );
4112
+ }
4113
+ function classHintsForPattern(projectRoot, ids) {
4114
+ const pack = readProjectPatternPack(projectRoot);
4115
+ const classes = /* @__PURE__ */ new Set();
4116
+ for (const pattern of pack?.patterns ?? []) {
4117
+ if (!ids.includes(String(pattern.id))) continue;
4118
+ for (const hint of pattern.classHints ?? []) classes.add(hint);
4119
+ }
4120
+ return [...classes].slice(0, 12);
4121
+ }
4122
+ function sourceEvidence(projectRoot, ids) {
4123
+ const pack = readProjectPatternPack(projectRoot);
4124
+ const evidence = /* @__PURE__ */ new Set();
4125
+ for (const pattern of pack?.patterns ?? []) {
4126
+ if (!ids.includes(String(pattern.id))) continue;
4127
+ for (const path of pattern.componentPaths ?? []) evidence.add(path);
4128
+ for (const item of pattern.evidence ?? []) evidence.add(item);
4129
+ }
4130
+ return [...evidence].slice(0, 12);
4131
+ }
4132
+ function colorTokenNames(styling) {
4133
+ const names = new Set(Object.keys(styling.colors ?? {}));
4134
+ for (const variable of styling.cssVariables) {
4135
+ if (/color|bg|background|surface|text|foreground|border|primary|secondary|accent|muted/i.test(variable)) {
4136
+ names.add(variable);
4137
+ }
4138
+ }
4139
+ return [...names].slice(0, 40);
4140
+ }
4141
+ function createStyleBridgeProposal(input) {
4142
+ const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
4143
+ const theme = readThemeInventory(input.projectRoot);
4144
+ const routeCount = input.essence && typeof input.essence === "object" && "blueprint" in input.essence ? Object.keys(input.essence.blueprint?.routes ?? {}).length : 0;
4145
+ const target = input.essence && typeof input.essence === "object" && "meta" in input.essence ? String(input.essence.meta?.target ?? "") || null : null;
4146
+ const darkModeDetected = theme.darkModeDetected ?? input.styling.darkMode;
4147
+ const themeModes = theme.modes.length > 0 ? theme.modes : darkModeDetected ? ["base", "dark"] : ["base"];
4148
+ const themeVariantIds = theme.variantIds.length > 0 ? theme.variantIds : themeModes.filter((mode) => mode !== "base");
4149
+ return {
4150
+ version: 1,
4151
+ status: "proposal",
4152
+ generatedAt,
4153
+ source: "decantr codify --style-bridge",
4154
+ 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.",
4155
+ adoption: {
4156
+ mode: "style-bridge",
4157
+ workflowMode: "brownfield-attach",
4158
+ sourceAuthority: "Existing production source stays authoritative.",
4159
+ styleAuthority: "Use these mappings to translate Decantr concepts into project-owned tokens, classes, and components.",
4160
+ notRuntimeTakeover: true,
4161
+ authorityPrecedence: [
4162
+ "existing production source",
4163
+ "accepted style bridge",
4164
+ "accepted local patterns and rules",
4165
+ "Essence V4 contract",
4166
+ "hosted registry patterns and execution packs as optional guidance"
4167
+ ]
4168
+ },
4169
+ project: {
4170
+ framework: input.detected.framework,
4171
+ packageManager: input.detected.packageManager,
4172
+ target,
4173
+ routeCount
4174
+ },
4175
+ styling: {
4176
+ approach: input.styling.approach,
4177
+ configFile: input.styling.configFile ?? null,
4178
+ darkModeDetected,
4179
+ cssVariables: input.styling.cssVariables.slice(0, 80),
4180
+ colorTokenNames: colorTokenNames(input.styling),
4181
+ themeModes,
4182
+ themeVariantIds
4183
+ },
4184
+ mappings: [
4185
+ {
4186
+ id: "surface",
4187
+ label: "Surfaces and cards",
4188
+ decantrIntent: "surface background, card treatment, border, radius, depth, and hover state",
4189
+ projectAuthority: "Use the app card/surface primitives, tokens, and accepted local law.",
4190
+ tokenHints: tokenHints(input.styling, /surface|card|panel|bg|background|border|shadow|radius/i),
4191
+ classHints: classHintsForPattern(input.projectRoot, ["surface-card"]),
4192
+ sourceEvidence: sourceEvidence(input.projectRoot, ["surface-card"]),
4193
+ guardrails: [
4194
+ "Do not invent a new card color/radius/shadow recipe without updating local law.",
4195
+ "Do not add Decantr CSS d-* classes unless adoption mode changes to decantr-css."
4196
+ ]
4197
+ },
4198
+ {
4199
+ id: "action",
4200
+ label: "Actions and buttons",
4201
+ decantrIntent: "primary, secondary, tertiary, destructive, icon-only, loading, and disabled action states",
4202
+ projectAuthority: "Use the app button/action primitives and local variant names.",
4203
+ tokenHints: tokenHints(input.styling, /primary|secondary|accent|danger|error|destructive|focus/i),
4204
+ classHints: classHintsForPattern(input.projectRoot, ["button"]),
4205
+ sourceEvidence: sourceEvidence(input.projectRoot, ["button"]),
4206
+ guardrails: [
4207
+ "Map any new action style to primary/secondary/tertiary/destructive/icon before coding.",
4208
+ "Avoid raw button markup when a project-owned primitive exists."
4209
+ ]
4210
+ },
4211
+ {
4212
+ id: "focus-accessibility",
4213
+ label: "Focus and accessibility",
4214
+ decantrIntent: "visible focus, keyboard clarity, contrast, and reduced-motion safety",
4215
+ projectAuthority: "Use the app accessibility classes, focus tokens, and framework conventions.",
4216
+ tokenHints: tokenHints(input.styling, /focus|ring|outline|contrast|motion|duration/i),
4217
+ classHints: [],
4218
+ sourceEvidence: [],
4219
+ guardrails: [
4220
+ "Every new interactive control needs visible focus evidence.",
4221
+ "Motion should honor prefers-reduced-motion or an existing app motion helper."
4222
+ ]
4223
+ },
4224
+ {
4225
+ id: "layout-density",
4226
+ label: "Layout density and spacing",
4227
+ decantrIntent: "route gutters, section gaps, component padding, density, and responsive rhythm",
4228
+ projectAuthority: "Use existing layout wrappers, shell primitives, and spacing tokens/classes.",
4229
+ tokenHints: tokenHints(input.styling, /space|spacing|gap|gutter|container|radius/i),
4230
+ classHints: classHintsForPattern(input.projectRoot, ["page-shell"]),
4231
+ sourceEvidence: sourceEvidence(input.projectRoot, ["page-shell"]),
4232
+ guardrails: [
4233
+ "Do not let each page invent independent max-width, gutters, or scroll ownership.",
4234
+ "Use the detected shell/layout authority before adding a new wrapper."
4235
+ ]
4236
+ },
4237
+ {
4238
+ id: "theme-variant",
4239
+ label: "Theme variants",
4240
+ decantrIntent: "light, dark, brand, tenant, seasonal, and density variants",
4241
+ projectAuthority: "Use the app theme provider, data attributes, CSS variables, or Tailwind mode strategy.",
4242
+ tokenHints: tokenHints(input.styling, /theme|dark|light|brand|tenant|mode|color/i),
4243
+ classHints: classHintsForPattern(input.projectRoot, ["theme-variant"]),
4244
+ sourceEvidence: sourceEvidence(input.projectRoot, ["theme-variant"]),
4245
+ guardrails: [
4246
+ "Keep theme modes documented in .decantr/theme-inventory.json and this bridge.",
4247
+ "Do not treat theme switcher container classes as standalone theme variants."
4248
+ ]
4249
+ }
4250
+ ],
4251
+ rules: [
4252
+ "The bridge is advisory until accepted; after acceptance, task/doctor/CI should surface it as Hybrid authority.",
4253
+ "The bridge does not make hosted registry patterns enforceable. Map hosted concepts into local law first.",
4254
+ "Keep deterministic blocking checks in .decantr/rules.json, ESLint, Biome, tests, or visual regression."
4255
+ ],
4256
+ nextSteps: [
4257
+ "Review token and class hints. Replace generic hints with the exact project tokens/classes the team owns.",
4258
+ "Run decantr codify --accept to promote the proposal to .decantr/style-bridge.json.",
4259
+ "Use decantr task <route> before LLM edits so the style bridge appears in task context.",
4260
+ "Run decantr ci or decantr verify after edits to keep local law and Project Health visible."
4261
+ ]
4262
+ };
4263
+ }
4264
+ function writeStyleBridgeProposal(projectRoot, proposal) {
4265
+ const decantrDir = join16(projectRoot, ".decantr");
4266
+ mkdirSync9(decantrDir, { recursive: true });
4267
+ const path = styleBridgeProposalPath(projectRoot);
4268
+ writeJsonFile(path, proposal);
4269
+ return path;
4270
+ }
4271
+ function acceptStyleBridge(projectRoot) {
4272
+ const proposal = readStyleBridgeProposal(projectRoot);
4273
+ if (!proposal) return null;
4274
+ const accepted = {
4275
+ ...proposal,
4276
+ status: "accepted",
4277
+ acceptedAt: (/* @__PURE__ */ new Date()).toISOString()
4278
+ };
4279
+ const path = styleBridgePath(projectRoot);
4280
+ writeJsonFile(path, accepted);
4281
+ const projectJsonPath = join16(projectRoot, ".decantr", "project.json");
4282
+ const projectJson = readJsonFile2(projectJsonPath) ?? {};
4283
+ const initialized = typeof projectJson.initialized === "object" && projectJson.initialized !== null ? projectJson.initialized : {};
4284
+ writeJsonFile(projectJsonPath, {
4285
+ ...projectJson,
4286
+ initialized: {
4287
+ ...initialized,
4288
+ workflowMode: initialized.workflowMode ?? "brownfield-attach",
4289
+ adoptionMode: "style-bridge"
4290
+ }
4291
+ });
4292
+ return path;
4293
+ }
4294
+ function createStyleBridgeTaskSummary(projectRoot) {
4295
+ const bridge = readStyleBridge(projectRoot);
4296
+ return {
4297
+ path: bridge ? ".decantr/style-bridge.json" : null,
4298
+ status: bridge?.status ?? null,
4299
+ mappingCount: bridge?.mappings?.length ?? 0,
4300
+ stylingApproach: bridge?.styling?.approach ?? null,
4301
+ themeModes: bridge?.styling?.themeModes ?? [],
4302
+ mappings: bridge?.mappings?.map((mapping) => ({
4303
+ id: mapping.id,
4304
+ label: mapping.label,
4305
+ tokenHints: mapping.tokenHints.slice(0, 6),
4306
+ classHints: mapping.classHints.slice(0, 4),
4307
+ guardrails: mapping.guardrails.slice(0, 3)
4308
+ })) ?? []
4309
+ };
4310
+ }
4311
+ function styleBridgeMatches(projectRoot, query) {
4312
+ if (!projectRoot) return [];
4313
+ const bridge = readStyleBridge(projectRoot);
4314
+ if (!bridge) return [];
4315
+ 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]);
4316
+ if (terms.length === 0) return [];
4317
+ return bridge.mappings.map((mapping) => {
4318
+ const haystack = [
4319
+ mapping.id,
4320
+ mapping.label,
4321
+ mapping.decantrIntent,
4322
+ mapping.projectAuthority,
4323
+ ...mapping.tokenHints,
4324
+ ...mapping.classHints,
4325
+ ...mapping.guardrails
4326
+ ].join(" ").toLowerCase();
4327
+ const score = terms.reduce((sum, term) => sum + (haystack.includes(term) ? 1 : 0), 0);
4328
+ return {
4329
+ id: mapping.id,
4330
+ label: mapping.label,
4331
+ score,
4332
+ tokenHints: mapping.tokenHints.slice(0, 4),
4333
+ classHints: mapping.classHints.slice(0, 3)
4334
+ };
4335
+ }).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, 5);
4336
+ }
4337
+
3751
4338
  // src/commands/ci.ts
3752
4339
  var BOLD2 = "\x1B[1m";
3753
4340
  var DIM3 = "\x1B[2m";
@@ -3756,9 +4343,9 @@ var RED2 = "\x1B[31m";
3756
4343
  var RESET3 = "\x1B[0m";
3757
4344
  var CI_SCHEMA = "https://decantr.ai/schemas/decantr-ci-report.v1.json";
3758
4345
  function readJson(path) {
3759
- if (!existsSync14(path)) return null;
4346
+ if (!existsSync15(path)) return null;
3760
4347
  try {
3761
- return JSON.parse(readFileSync12(path, "utf-8"));
4348
+ return JSON.parse(readFileSync13(path, "utf-8"));
3762
4349
  } catch {
3763
4350
  return null;
3764
4351
  }
@@ -3802,21 +4389,21 @@ function parseProvider(value) {
3802
4389
  throw new Error("Invalid --provider value. Use github or generic.");
3803
4390
  }
3804
4391
  function detectPackageManager2(root) {
3805
- const pkg = readJson(join16(root, "package.json"));
4392
+ const pkg = readJson(join17(root, "package.json"));
3806
4393
  const declared = pkg?.packageManager?.split("@")[0];
3807
4394
  if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
3808
4395
  return declared;
3809
4396
  }
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";
4397
+ if (existsSync15(join17(root, "pnpm-lock.yaml"))) return "pnpm";
4398
+ if (existsSync15(join17(root, "package-lock.json"))) return "npm";
4399
+ if (existsSync15(join17(root, "yarn.lock"))) return "yarn";
4400
+ if (existsSync15(join17(root, "bun.lock")) || existsSync15(join17(root, "bun.lockb"))) return "bun";
3814
4401
  return "unknown";
3815
4402
  }
3816
4403
  function hasWorkspaceMarker(root) {
3817
- const pkg = readJson(join16(root, "package.json"));
4404
+ const pkg = readJson(join17(root, "package.json"));
3818
4405
  return Boolean(
3819
- existsSync14(join16(root, "pnpm-workspace.yaml")) || existsSync14(join16(root, "turbo.json")) || existsSync14(join16(root, "nx.json")) || pkg?.workspaces
4406
+ existsSync15(join17(root, "pnpm-workspace.yaml")) || existsSync15(join17(root, "turbo.json")) || existsSync15(join17(root, "nx.json")) || pkg?.workspaces
3820
4407
  );
3821
4408
  }
3822
4409
  function installCommand(packageManager) {
@@ -3862,7 +4449,7 @@ function decantrCommand(packageManager) {
3862
4449
  }
3863
4450
  }
3864
4451
  function localCliPinned(root) {
3865
- const pkg = readJson(join16(root, "package.json"));
4452
+ const pkg = readJson(join17(root, "package.json"));
3866
4453
  return Boolean(pkg?.devDependencies?.["@decantr/cli"] || pkg?.dependencies?.["@decantr/cli"]);
3867
4454
  }
3868
4455
  function projectSlug(projectPath) {
@@ -3870,8 +4457,8 @@ function projectSlug(projectPath) {
3870
4457
  }
3871
4458
  function writeOutput(root, path, content) {
3872
4459
  const absolute = resolve(root, path);
3873
- mkdirSync9(dirname3(absolute), { recursive: true });
3874
- writeFileSync10(absolute, content, "utf-8");
4460
+ mkdirSync10(dirname3(absolute), { recursive: true });
4461
+ writeFileSync11(absolute, content, "utf-8");
3875
4462
  }
3876
4463
  function summarizeLocalLaw(projectRoot) {
3877
4464
  const validation = validateLocalLaw(projectRoot);
@@ -3893,14 +4480,36 @@ function summarizeLocalLaw(projectRoot) {
3893
4480
  warnCount: validation.findings.filter((finding) => finding.severity === "warn").length + validation.warnings.length
3894
4481
  };
3895
4482
  }
4483
+ function summarizeStyleBridge(projectRoot) {
4484
+ const summary = createStyleBridgeTaskSummary(projectRoot);
4485
+ const warnings = [];
4486
+ if (summary.path && summary.mappingCount === 0) {
4487
+ warnings.push(".decantr/style-bridge.json has no mappings.");
4488
+ }
4489
+ return {
4490
+ checked: Boolean(summary.path),
4491
+ present: Boolean(summary.path),
4492
+ status: summary.status,
4493
+ mappingCount: summary.mappingCount,
4494
+ stylingApproach: summary.stylingApproach,
4495
+ themeModes: summary.themeModes,
4496
+ warnings
4497
+ };
4498
+ }
3896
4499
  function localLawFails(summary, failOn) {
3897
4500
  if (failOn === "none" || !summary.checked) return false;
3898
4501
  if (summary.errorCount > 0) return true;
3899
4502
  return failOn === "warn" && summary.warnCount > 0;
3900
4503
  }
3901
- function projectCiStatus(health, localLaw) {
4504
+ function styleBridgeFails(summary, failOn) {
4505
+ if (failOn === "none" || !summary.checked) return false;
4506
+ return failOn === "warn" && summary.warnings.length > 0;
4507
+ }
4508
+ function projectCiStatus(health, localLaw, styleBridge) {
3902
4509
  if (health.status === "error" || localLaw.errorCount > 0) return "error";
3903
- if (health.status === "warning" || localLaw.warnCount > 0) return "warning";
4510
+ if (health.status === "warning" || localLaw.warnCount > 0 || styleBridge.warnings.length > 0) {
4511
+ return "warning";
4512
+ }
3904
4513
  return health.status;
3905
4514
  }
3906
4515
  function formatLocalLawText(summary, health) {
@@ -3916,6 +4525,9 @@ function formatLocalLawText(summary, health) {
3916
4525
  lines.push(
3917
4526
  ` Patterns: ${summary.patternsPresent ? "present" : "missing"} | Rules: ${summary.rulesPresent ? "present" : "missing"}`
3918
4527
  );
4528
+ lines.push(
4529
+ summary.rulesPresent ? " Enforcement: Decantr scans accepted .decantr/rules.json; this command's --fail-on setting controls whether findings block." : " Enforcement: advisory only until .decantr/rules.json is accepted."
4530
+ );
3919
4531
  lines.push(` Findings: ${summary.errorCount} error(s), ${summary.warnCount} warning(s)`);
3920
4532
  for (const warning of summary.warnings.slice(0, 5)) {
3921
4533
  lines.push(` ${DIM3}[WARN] ${warning}${RESET3}`);
@@ -3933,6 +4545,28 @@ function formatLocalLawText(summary, health) {
3933
4545
  return `${lines.join("\n")}
3934
4546
  `;
3935
4547
  }
4548
+ function formatStyleBridgeText(summary) {
4549
+ const lines = ["", `${BOLD2}Project-owned style bridge:${RESET3}`];
4550
+ if (!summary.checked) {
4551
+ lines.push(" Not active for this project.");
4552
+ return `${lines.join("\n")}
4553
+ `;
4554
+ }
4555
+ lines.push(
4556
+ ` Present: ${summary.present ? "yes" : "no"} | Mappings: ${summary.mappingCount} | Styling: ${summary.stylingApproach ?? "unknown"}`
4557
+ );
4558
+ lines.push(
4559
+ " Enforcement: advisory style-intent mapping; pair with accepted local rules, lint, tests, or visual regression when it should block."
4560
+ );
4561
+ if (summary.themeModes.length > 0) {
4562
+ lines.push(` Theme modes: ${summary.themeModes.join(", ")}`);
4563
+ }
4564
+ for (const warning of summary.warnings.slice(0, 5)) {
4565
+ lines.push(` ${DIM3}[WARN] ${warning}${RESET3}`);
4566
+ }
4567
+ return `${lines.join("\n")}
4568
+ `;
4569
+ }
3936
4570
  function formatLocalLawMarkdown(summary, health) {
3937
4571
  const lines = ["## Project-Owned Local Law", ""];
3938
4572
  if (!summary.checked) {
@@ -3948,6 +4582,9 @@ function formatLocalLawMarkdown(summary, health) {
3948
4582
  lines.push(
3949
4583
  `Patterns: **${summary.patternsPresent ? "present" : "missing"}** \xB7 Rules: **${summary.rulesPresent ? "present" : "missing"}**`
3950
4584
  );
4585
+ lines.push(
4586
+ summary.rulesPresent ? "Enforcement: Decantr scans accepted `.decantr/rules.json`; CI blocking depends on `--fail-on`." : "Enforcement: advisory only until `.decantr/rules.json` is accepted."
4587
+ );
3951
4588
  lines.push("");
3952
4589
  lines.push(`Findings: **${summary.errorCount} error(s), ${summary.warnCount} warning(s)**`);
3953
4590
  if (summary.warnings.length > 0) {
@@ -3966,6 +4603,30 @@ function formatLocalLawMarkdown(summary, health) {
3966
4603
  }
3967
4604
  return lines.join("\n");
3968
4605
  }
4606
+ function formatStyleBridgeMarkdown(summary) {
4607
+ const lines = ["## Project-Owned Style Bridge", ""];
4608
+ if (!summary.checked) {
4609
+ lines.push("Style bridge is not active for this project.");
4610
+ return lines.join("\n");
4611
+ }
4612
+ lines.push(
4613
+ `Present: **${summary.present ? "yes" : "no"}** \xB7 Mappings: **${summary.mappingCount}** \xB7 Styling: **${summary.stylingApproach ?? "unknown"}**`
4614
+ );
4615
+ lines.push("");
4616
+ lines.push(
4617
+ "Enforcement: advisory style-intent mapping; pair with accepted local rules, lint, tests, or visual regression when it should block."
4618
+ );
4619
+ if (summary.themeModes.length > 0) {
4620
+ lines.push("", `Theme modes: ${summary.themeModes.map((mode) => `\`${mode}\``).join(", ")}`);
4621
+ }
4622
+ if (summary.warnings.length > 0) {
4623
+ lines.push("");
4624
+ for (const warning of summary.warnings.slice(0, 5)) {
4625
+ lines.push(`- Warning: ${warning}`);
4626
+ }
4627
+ }
4628
+ return lines.join("\n");
4629
+ }
3969
4630
  function formatProjectCiMarkdown(report) {
3970
4631
  const lines = [
3971
4632
  "# Decantr CI",
@@ -3975,10 +4636,13 @@ function formatProjectCiMarkdown(report) {
3975
4636
  `- Status: **${report.status}**`,
3976
4637
  `- Fail on: \`${report.failOn}\``,
3977
4638
  `- Local law: ${report.localLaw.checked ? `${report.localLaw.errorCount} error(s), ${report.localLaw.warnCount} warning(s)` : "not accepted yet"}`,
4639
+ `- Style bridge: ${report.styleBridge.checked ? `${report.styleBridge.mappingCount} mapping(s)` : "not active"}`,
3978
4640
  "",
3979
4641
  formatProjectHealthMarkdown(report.health),
3980
4642
  "",
3981
- formatLocalLawMarkdown(report.localLaw, report.health)
4643
+ formatLocalLawMarkdown(report.localLaw, report.health),
4644
+ "",
4645
+ formatStyleBridgeMarkdown(report.styleBridge)
3982
4646
  ];
3983
4647
  return `${lines.join("\n")}
3984
4648
  `;
@@ -4069,7 +4733,7 @@ jobs:
4069
4733
  }
4070
4734
  function writeCiInit(root, options) {
4071
4735
  const workspaceInfo = resolveWorkspaceInfo(root, options.project);
4072
- if (options.project && !existsSync14(workspaceInfo.appRoot)) {
4736
+ if (options.project && !existsSync15(workspaceInfo.appRoot)) {
4073
4737
  throw new Error(`Project path does not exist: ${options.project}`);
4074
4738
  }
4075
4739
  if (workspaceInfo.requiresProjectSelection && !options.workspace) {
@@ -4092,7 +4756,7 @@ function writeCiInit(root, options) {
4092
4756
  if (provider === "generic") {
4093
4757
  const path2 = ".decantr/ci/decantr-ci.sh";
4094
4758
  const absolute2 = resolve(outputRoot, path2);
4095
- if (existsSync14(absolute2) && !options.force) {
4759
+ if (existsSync15(absolute2) && !options.force) {
4096
4760
  throw new Error(`${path2} already exists. Re-run with --force to replace it.`);
4097
4761
  }
4098
4762
  writeOutput(
@@ -4113,7 +4777,7 @@ function writeCiInit(root, options) {
4113
4777
  }
4114
4778
  const path = ".github/workflows/decantr-ci.yml";
4115
4779
  const absolute = resolve(outputRoot, path);
4116
- if (existsSync14(absolute) && !options.force) {
4780
+ if (existsSync15(absolute) && !options.force) {
4117
4781
  throw new Error(`${path} already exists. Re-run with --force to replace it.`);
4118
4782
  }
4119
4783
  writeOutput(
@@ -4162,7 +4826,7 @@ async function runWorkspaceCi(root, options) {
4162
4826
  }
4163
4827
  async function runProjectCi(root, options) {
4164
4828
  const workspaceInfo = resolveWorkspaceInfo(root, options.project);
4165
- if (options.project && !existsSync14(workspaceInfo.appRoot)) {
4829
+ if (options.project && !existsSync15(workspaceInfo.appRoot)) {
4166
4830
  console.error(`${RED2}Project path does not exist: ${options.project}${RESET3}`);
4167
4831
  return 1;
4168
4832
  }
@@ -4175,6 +4839,7 @@ async function runProjectCi(root, options) {
4175
4839
  const failOn = options.failOn ?? "error";
4176
4840
  const health = await createProjectHealthReport(workspaceInfo.appRoot);
4177
4841
  const localLaw = summarizeLocalLaw(workspaceInfo.appRoot);
4842
+ const styleBridge = summarizeStyleBridge(workspaceInfo.appRoot);
4178
4843
  const projectPath = workspaceInfo.appRoot === workspaceInfo.workspaceRoot ? null : workspaceInfo.appRoot.replace(`${workspaceInfo.workspaceRoot}/`, "");
4179
4844
  const report = {
4180
4845
  $schema: CI_SCHEMA,
@@ -4182,9 +4847,10 @@ async function runProjectCi(root, options) {
4182
4847
  mode: "project",
4183
4848
  projectPath,
4184
4849
  failOn,
4185
- status: projectCiStatus(health, localLaw),
4850
+ status: projectCiStatus(health, localLaw, styleBridge),
4186
4851
  health,
4187
- localLaw
4852
+ localLaw,
4853
+ styleBridge
4188
4854
  };
4189
4855
  const json = `${JSON.stringify(report, null, 2)}
4190
4856
  `;
@@ -4195,9 +4861,11 @@ async function runProjectCi(root, options) {
4195
4861
  if (options.json) process.stdout.write(json);
4196
4862
  else if (options.markdown) process.stdout.write(markdown);
4197
4863
  else
4198
- process.stdout.write(`${formatProjectHealthText(health)}${formatLocalLawText(localLaw, health)}`);
4864
+ process.stdout.write(
4865
+ `${formatProjectHealthText(health)}${formatLocalLawText(localLaw, health)}${formatStyleBridgeText(styleBridge)}`
4866
+ );
4199
4867
  }
4200
- return shouldFailHealth(health, failOn) || localLawFails(localLaw, failOn) ? 1 : 0;
4868
+ return shouldFailHealth(health, failOn) || localLawFails(localLaw, failOn) || styleBridgeFails(styleBridge, failOn) ? 1 : 0;
4201
4869
  }
4202
4870
  function cmdCiHelp() {
4203
4871
  console.log(`
@@ -4232,8 +4900,8 @@ async function cmdCi(args = ["ci"], root = process.cwd()) {
4232
4900
  }
4233
4901
 
4234
4902
  // src/commands/create.ts
4235
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
4236
- import { join as join17 } from "path";
4903
+ import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync12 } from "fs";
4904
+ import { join as join18 } from "path";
4237
4905
  import {
4238
4906
  CONTENT_TYPE_TO_API_CONTENT_TYPE,
4239
4907
  CONTENT_TYPES
@@ -4429,23 +5097,23 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
4429
5097
  }
4430
5098
  const contentType = type;
4431
5099
  const plural = PLURAL[contentType];
4432
- const customDir = join17(projectRoot, ".decantr", "custom", plural);
4433
- const filePath = join17(customDir, `${name}.json`);
4434
- if (existsSync15(filePath)) {
5100
+ const customDir = join18(projectRoot, ".decantr", "custom", plural);
5101
+ const filePath = join18(customDir, `${name}.json`);
5102
+ if (existsSync16(filePath)) {
4435
5103
  console.error(`${type} "${name}" already exists at ${filePath}`);
4436
5104
  process.exitCode = 1;
4437
5105
  return;
4438
5106
  }
4439
- mkdirSync10(customDir, { recursive: true });
5107
+ mkdirSync11(customDir, { recursive: true });
4440
5108
  const skeleton = getSkeleton(contentType, name, humanizeId(name));
4441
- writeFileSync11(filePath, JSON.stringify(skeleton, null, 2));
5109
+ writeFileSync12(filePath, JSON.stringify(skeleton, null, 2));
4442
5110
  console.log(`Created ${type} "${name}" at ${filePath}`);
4443
5111
  console.log(`Edit it, then publish with: decantr publish ${type} ${name}`);
4444
5112
  }
4445
5113
 
4446
5114
  // 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";
5115
+ import { existsSync as existsSync17, readdirSync as readdirSync6, readFileSync as readFileSync14 } from "fs";
5116
+ import { dirname as dirname4, join as join19, relative as relative5 } from "path";
4449
5117
  import { fileURLToPath } from "url";
4450
5118
  import { isV4 as isV44 } from "@decantr/essence-spec";
4451
5119
  import { collectMissingPackManifestFiles } from "@decantr/verifier";
@@ -4457,25 +5125,25 @@ var YELLOW3 = "\x1B[33m";
4457
5125
  var CYAN2 = "\x1B[36m";
4458
5126
  var RESET4 = "\x1B[0m";
4459
5127
  function readJson2(path) {
4460
- if (!existsSync16(path)) return null;
5128
+ if (!existsSync17(path)) return null;
4461
5129
  try {
4462
- return JSON.parse(readFileSync13(path, "utf-8"));
5130
+ return JSON.parse(readFileSync14(path, "utf-8"));
4463
5131
  } catch {
4464
5132
  return null;
4465
5133
  }
4466
5134
  }
4467
5135
  function isContractOnlyProject(projectRoot) {
4468
- const projectJson = readJson2(join18(projectRoot, ".decantr", "project.json"));
4469
- return projectJson?.initialized?.adoptionMode === "contract-only";
5136
+ const projectJson = readJson2(join19(projectRoot, ".decantr", "project.json"));
5137
+ return projectJson?.initialized?.adoptionMode === "contract-only" || projectJson?.initialized?.adoptionMode === "style-bridge";
4470
5138
  }
4471
5139
  function readCliPackageVersion() {
4472
- const packagePath = join18(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4473
- const srcPackagePath = join18(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
5140
+ const packagePath = join19(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
5141
+ const srcPackagePath = join19(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
4474
5142
  const pkg = readJson2(packagePath) ?? readJson2(srcPackagePath);
4475
5143
  return pkg?.version ?? "unknown";
4476
5144
  }
4477
5145
  function readPackageJson2(dir) {
4478
- return readJson2(join18(dir, "package.json"));
5146
+ return readJson2(join19(dir, "package.json"));
4479
5147
  }
4480
5148
  function detectPackageManager3(root) {
4481
5149
  const pkg = readPackageJson2(root);
@@ -4483,10 +5151,10 @@ function detectPackageManager3(root) {
4483
5151
  if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
4484
5152
  return declared;
4485
5153
  }
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";
5154
+ if (existsSync17(join19(root, "pnpm-lock.yaml"))) return "pnpm";
5155
+ if (existsSync17(join19(root, "package-lock.json"))) return "npm";
5156
+ if (existsSync17(join19(root, "yarn.lock"))) return "yarn";
5157
+ if (existsSync17(join19(root, "bun.lock")) || existsSync17(join19(root, "bun.lockb"))) return "bun";
4490
5158
  return "unknown";
4491
5159
  }
4492
5160
  function localCliDependency(root) {
@@ -4496,7 +5164,7 @@ function localCliDependency(root) {
4496
5164
  function hasWorkspaceMarker2(root) {
4497
5165
  const pkg = readPackageJson2(root);
4498
5166
  return Boolean(
4499
- existsSync16(join18(root, "pnpm-workspace.yaml")) || existsSync16(join18(root, "turbo.json")) || existsSync16(join18(root, "nx.json")) || pkg?.workspaces
5167
+ existsSync17(join19(root, "pnpm-workspace.yaml")) || existsSync17(join19(root, "turbo.json")) || existsSync17(join19(root, "nx.json")) || pkg?.workspaces
4500
5168
  );
4501
5169
  }
4502
5170
  function pinCliCommand2(packageManager, root) {
@@ -4519,8 +5187,8 @@ function rel(root, path) {
4519
5187
  }
4520
5188
  function hasAnyFile(dir, names) {
4521
5189
  for (const name of names) {
4522
- const path = join18(dir, name);
4523
- if (existsSync16(path)) return name;
5190
+ const path = join19(dir, name);
5191
+ if (existsSync17(path)) return name;
4524
5192
  }
4525
5193
  return null;
4526
5194
  }
@@ -4542,7 +5210,7 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
4542
5210
  "libs/design-system"
4543
5211
  ];
4544
5212
  for (const candidate of sharedCandidates) {
4545
- if (existsSync16(join18(workspaceRoot, candidate))) found.add(candidate);
5213
+ if (existsSync17(join19(workspaceRoot, candidate))) found.add(candidate);
4546
5214
  }
4547
5215
  for (const root of [appRoot, workspaceRoot]) {
4548
5216
  const label = root === appRoot ? "app" : "workspace";
@@ -4553,9 +5221,9 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
4553
5221
  "tailwind.config.cjs"
4554
5222
  ]);
4555
5223
  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`);
5224
+ if (existsSync17(join19(root, ".storybook"))) found.add(`${label}:.storybook`);
5225
+ if (existsSync17(join19(root, "components", "ui"))) found.add(`${label}:components/ui`);
5226
+ if (existsSync17(join19(root, "src", "components", "ui"))) found.add(`${label}:src/components/ui`);
4559
5227
  if (packageHasDependency(root, ["@storybook/react", "storybook"]))
4560
5228
  found.add(`${label}:storybook`);
4561
5229
  if (packageHasDependency(root, ["tailwindcss"])) found.add(`${label}:tailwindcss`);
@@ -4567,18 +5235,18 @@ function detectDesignAuthority(workspaceRoot, appRoot) {
4567
5235
  }
4568
5236
  function findCiFiles(root) {
4569
5237
  const files = [];
4570
- const workflows = join18(root, ".github", "workflows");
4571
- if (existsSync16(workflows)) {
5238
+ const workflows = join19(root, ".github", "workflows");
5239
+ if (existsSync17(workflows)) {
4572
5240
  for (const entry of readdirSync6(workflows, { withFileTypes: true })) {
4573
5241
  if (!entry.isFile()) continue;
4574
- const path = join18(workflows, entry.name);
4575
- const text = readFileSync13(path, "utf-8");
5242
+ const path = join19(workflows, entry.name);
5243
+ const text = readFileSync14(path, "utf-8");
4576
5244
  if (text.includes("decantr")) files.push(rel(root, path));
4577
5245
  }
4578
5246
  }
4579
5247
  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")) {
5248
+ const path = join19(root, candidate);
5249
+ if (existsSync17(path) && readFileSync14(path, "utf-8").includes("decantr")) {
4582
5250
  files.push(candidate);
4583
5251
  }
4584
5252
  }
@@ -4618,15 +5286,17 @@ function deriveAdoptionLane(input) {
4618
5286
  };
4619
5287
  }
4620
5288
  const hasLocalLaw = input.localPatternsPresent || input.localRulesPresent;
5289
+ const hasStyleBridge = input.styleBridgePresent || input.adoptionMode === "style-bridge";
4621
5290
  if (input.workflowMode === "hybrid-compose") {
4622
5291
  return {
4623
5292
  id: "hybrid-compose",
4624
5293
  label: "Hybrid composition",
4625
5294
  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",
5295
+ 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
5296
  activeAuthorities: [
4628
5297
  "existing source",
4629
5298
  "Essence V4 contract",
5299
+ hasStyleBridge ? "accepted style bridge" : "no style bridge",
4630
5300
  hasLocalLaw ? "accepted local law" : "reviewed Hybrid choices",
4631
5301
  input.packManifestPresent ? "hosted execution packs" : "optional hosted packs"
4632
5302
  ],
@@ -4644,13 +5314,18 @@ function deriveAdoptionLane(input) {
4644
5314
  nextChoice: "Keep Decantr CSS usage explicit and validate route changes with task and verify."
4645
5315
  };
4646
5316
  }
4647
- if (input.adoptionMode === "style-bridge") {
5317
+ if (hasStyleBridge) {
4648
5318
  return {
4649
5319
  id: "hybrid-style-bridge",
4650
5320
  label: "Hybrid style bridge",
4651
5321
  sourceAuthority: "Existing app plus Decantr intent mapped through a style bridge",
4652
5322
  styleAuthority: "Style bridge over the existing app styling system",
4653
- activeAuthorities: ["existing source", "Essence V4 contract", "style bridge"],
5323
+ activeAuthorities: [
5324
+ "existing source",
5325
+ "Essence V4 contract",
5326
+ "accepted style bridge",
5327
+ hasLocalLaw ? "accepted local patterns/rules" : "optional local law"
5328
+ ],
4654
5329
  nextChoice: "Use local law to decide which component families the bridge governs before making it strict."
4655
5330
  };
4656
5331
  }
@@ -4708,18 +5383,18 @@ function buildDoctorReport(root, args) {
4708
5383
  const workspaceInfo = resolveWorkspaceInfo(root, projectArg);
4709
5384
  const workspaceRoot = workspaceInfo.workspaceRoot;
4710
5385
  const appRoot = workspaceMode ? workspaceRoot : workspaceInfo.appRoot;
4711
- const projectMissing = Boolean(projectArg && !existsSync16(appRoot));
5386
+ const projectMissing = Boolean(projectArg && !existsSync17(appRoot));
4712
5387
  const projectPath = appRoot === workspaceRoot ? null : rel(workspaceRoot, appRoot);
4713
5388
  const packageManager = detectPackageManager3(workspaceRoot);
4714
5389
  const cliDependency = localCliDependency(workspaceRoot);
4715
5390
  const detected = detectProject(appRoot);
4716
- const projectJson = readJson2(join18(appRoot, ".decantr", "project.json"));
4717
- const essence = readJson2(join18(appRoot, "decantr.essence.json"));
5391
+ const projectJson = readJson2(join19(appRoot, ".decantr", "project.json"));
5392
+ const essence = readJson2(join19(appRoot, "decantr.essence.json"));
4718
5393
  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));
5394
+ const contextDir = join19(appRoot, ".decantr", "context");
5395
+ const packManifestPresent = existsSync17(join19(contextDir, "pack-manifest.json"));
5396
+ const reviewPackPresent = existsSync17(join19(contextDir, "review-pack.json"));
5397
+ const artifactReadmePresent = existsSync17(join19(appRoot, ARTIFACT_README_PATH));
4723
5398
  const projects = listWorkspaceProjects(workspaceRoot);
4724
5399
  const candidates = listWorkspaceCandidates(workspaceRoot, projects).map((candidate) => ({
4725
5400
  path: candidate.path,
@@ -4729,21 +5404,23 @@ function buildDoctorReport(root, args) {
4729
5404
  const ciFiles = findCiFiles(workspaceRoot);
4730
5405
  const workflowMode = projectJson?.initialized?.workflowMode ?? null;
4731
5406
  const adoptionMode = projectJson?.initialized?.adoptionMode ?? null;
4732
- const packHydrationOptional = adoptionMode === "contract-only";
4733
- const localPatternsPresent = existsSync16(localPatternsPath(appRoot));
4734
- const localRulesPresent = existsSync16(localRulesPath(appRoot));
5407
+ const packHydrationOptional = adoptionMode === "contract-only" || adoptionMode === "style-bridge";
5408
+ const localPatternsPresent = existsSync17(localPatternsPath(appRoot));
5409
+ const localRulesPresent = existsSync17(localRulesPath(appRoot));
5410
+ const styleBridgePresent = existsSync17(styleBridgePath(appRoot));
5411
+ const styleBridgeProposalPresent = existsSync17(styleBridgeProposalPath(appRoot));
4735
5412
  const missingPackReferences = workspaceMode ? projects.flatMap(
4736
- (project) => collectMissingPackManifestFiles(join18(workspaceRoot, project.path)).map(
5413
+ (project) => collectMissingPackManifestFiles(join19(workspaceRoot, project.path)).map(
4737
5414
  (missing) => `${project.path}/${missing.relativePath}`
4738
5415
  )
4739
5416
  ) : collectMissingPackManifestFiles(appRoot).map((missing) => missing.relativePath);
4740
5417
  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"));
5418
+ const projectContextDir = join19(workspaceRoot, projectPath2, ".decantr", "context");
5419
+ return !isContractOnlyProject(join19(workspaceRoot, projectPath2)) && !existsSync17(join19(projectContextDir, "pack-manifest.json"));
4743
5420
  }) : [];
4744
5421
  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"));
5422
+ const projectContextDir = join19(workspaceRoot, projectPath2, ".decantr", "context");
5423
+ return !isContractOnlyProject(join19(workspaceRoot, projectPath2)) && !existsSync17(join19(projectContextDir, "review-pack.json"));
4747
5424
  }) : [];
4748
5425
  const issues = [];
4749
5426
  if (projectMissing) {
@@ -4800,7 +5477,7 @@ function buildDoctorReport(root, args) {
4800
5477
  nextCommand: "decantr refresh"
4801
5478
  });
4802
5479
  }
4803
- if (essenceVersion === "4.0.0" && !packHydrationOptional && (!existsSync16(contextDir) || !packManifestPresent)) {
5480
+ if (essenceVersion === "4.0.0" && !packHydrationOptional && (!existsSync17(contextDir) || !packManifestPresent)) {
4804
5481
  issues.push({
4805
5482
  category: "generated-artifact",
4806
5483
  severity: "warn",
@@ -4832,6 +5509,14 @@ function buildDoctorReport(root, args) {
4832
5509
  nextCommand: projectPath ? `decantr codify --from-audit --project ${projectPath}` : "decantr codify --from-audit"
4833
5510
  });
4834
5511
  }
5512
+ if (adoptionMode === "style-bridge" && !styleBridgePresent) {
5513
+ issues.push({
5514
+ category: "local-law",
5515
+ severity: "warn",
5516
+ message: "This app declares style-bridge adoption, but .decantr/style-bridge.json is missing.",
5517
+ nextCommand: styleBridgeProposalPresent ? projectPath ? `decantr codify --accept --project ${projectPath}` : "decantr codify --accept" : projectPath ? `decantr codify --style-bridge --project ${projectPath}` : "decantr codify --style-bridge"
5518
+ });
5519
+ }
4835
5520
  if ((essenceVersion === "4.0.0" || workspaceMode && projects.length > 0) && ciFiles.length === 0) {
4836
5521
  issues.push({
4837
5522
  category: "ci",
@@ -4859,6 +5544,7 @@ function buildDoctorReport(root, args) {
4859
5544
  adoptionMode,
4860
5545
  localPatternsPresent,
4861
5546
  localRulesPresent,
5547
+ styleBridgePresent,
4862
5548
  designAuthority,
4863
5549
  packManifestPresent
4864
5550
  });
@@ -4880,6 +5566,12 @@ function buildDoctorReport(root, args) {
4880
5566
  appendUnique(recommendedNextCommands, `decantr codify --from-audit${projectFlag}`);
4881
5567
  appendUnique(recommendedNextCommands, `decantr codify --accept${projectFlag}`);
4882
5568
  }
5569
+ if (adoptionMode === "style-bridge" && !styleBridgePresent) {
5570
+ appendUnique(
5571
+ recommendedNextCommands,
5572
+ styleBridgeProposalPresent ? `decantr codify --accept${projectFlag}` : `decantr codify --style-bridge${projectFlag}`
5573
+ );
5574
+ }
4883
5575
  appendUnique(
4884
5576
  recommendedNextCommands,
4885
5577
  issues.find((issue) => issue.category === "generated-artifact")?.nextCommand
@@ -4919,18 +5611,20 @@ function buildDoctorReport(root, args) {
4919
5611
  },
4920
5612
  generatedArtifacts: {
4921
5613
  contextDirPresent: workspaceMode ? projects.some(
4922
- (project) => existsSync16(join18(workspaceRoot, project.path, ".decantr", "context"))
4923
- ) : existsSync16(contextDir),
5614
+ (project) => existsSync17(join19(workspaceRoot, project.path, ".decantr", "context"))
5615
+ ) : existsSync17(contextDir),
4924
5616
  packManifestPresent: workspaceMode ? projects.length > 0 && workspaceProjectsMissingManifest.length === 0 : packManifestPresent,
4925
5617
  reviewPackPresent: workspaceMode ? projects.length > 0 && workspaceProjectsMissingReviewPack.length === 0 : reviewPackPresent,
4926
5618
  missingReferencedFiles: missingPackReferences.slice(0, 25)
4927
5619
  },
4928
5620
  localLaw: {
4929
5621
  patternsPresent: localPatternsPresent,
4930
- rulesPresent: localRulesPresent
5622
+ rulesPresent: localRulesPresent,
5623
+ styleBridgePresent,
5624
+ styleBridgeProposalPresent
4931
5625
  },
4932
5626
  visualEvidence: {
4933
- manifestPresent: existsSync16(join18(appRoot, ".decantr", "evidence", "visual-manifest.json"))
5627
+ manifestPresent: existsSync17(join19(appRoot, ".decantr", "evidence", "visual-manifest.json"))
4934
5628
  },
4935
5629
  lane,
4936
5630
  designAuthority,
@@ -4978,6 +5672,7 @@ function formatDoctorText(report) {
4978
5672
  `${BOLD3}Local Law:${RESET4}`,
4979
5673
  ` Local patterns: ${report.localLaw.patternsPresent ? "present" : "missing"}`,
4980
5674
  ` Local rules: ${report.localLaw.rulesPresent ? "present" : "missing"}`,
5675
+ ` Style bridge: ${report.localLaw.styleBridgePresent ? "present" : report.localLaw.styleBridgeProposalPresent ? "proposal pending" : "missing"}`,
4981
5676
  "",
4982
5677
  `${BOLD3}Workspace:${RESET4}`,
4983
5678
  ` Attached projects: ${report.workspace.attachedProjects.length}`,
@@ -5037,17 +5732,17 @@ async function cmdDoctor(args = ["doctor"], root = process.cwd()) {
5037
5732
  }
5038
5733
 
5039
5734
  // 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";
5735
+ import { existsSync as existsSync18, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "fs";
5736
+ import { dirname as dirname5, isAbsolute, join as join20 } from "path";
5042
5737
  var GREEN5 = "\x1B[32m";
5043
5738
  var RED4 = "\x1B[31m";
5044
5739
  var DIM5 = "\x1B[2m";
5045
5740
  var RESET5 = "\x1B[0m";
5046
5741
  function readAdoptionMode(projectRoot) {
5047
- const projectJsonPath = join19(projectRoot, ".decantr", "project.json");
5048
- if (!existsSync17(projectJsonPath)) return null;
5742
+ const projectJsonPath = join20(projectRoot, ".decantr", "project.json");
5743
+ if (!existsSync18(projectJsonPath)) return null;
5049
5744
  try {
5050
- const parsed = JSON.parse(readFileSync14(projectJsonPath, "utf-8"));
5745
+ const parsed = JSON.parse(readFileSync15(projectJsonPath, "utf-8"));
5051
5746
  return typeof parsed.initialized?.adoptionMode === "string" ? parsed.initialized.adoptionMode : null;
5052
5747
  } catch {
5053
5748
  return null;
@@ -5055,7 +5750,7 @@ function readAdoptionMode(projectRoot) {
5055
5750
  }
5056
5751
  function resolveOutputPath(projectRoot, output, fallback) {
5057
5752
  if (!output) return fallback;
5058
- return isAbsolute(output) ? output : join19(projectRoot, output);
5753
+ return isAbsolute(output) ? output : join20(projectRoot, output);
5059
5754
  }
5060
5755
  var SHADCN_MAP = {
5061
5756
  "--d-bg": "--background",
@@ -5216,21 +5911,21 @@ function generateFigmaTokens(tokens) {
5216
5911
  `;
5217
5912
  }
5218
5913
  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)) {
5914
+ const essencePath = join20(projectRoot, "decantr.essence.json");
5915
+ const tokensPath = join20(projectRoot, "src", "styles", "tokens.css");
5916
+ if (!existsSync18(essencePath)) {
5222
5917
  console.error(`${RED4}No decantr.essence.json found. Run \`decantr init\` first.${RESET5}`);
5223
5918
  process.exitCode = 1;
5224
5919
  return;
5225
5920
  }
5226
- if (!existsSync17(tokensPath)) {
5921
+ if (!existsSync18(tokensPath)) {
5227
5922
  const adoptionMode = readAdoptionMode(projectRoot);
5228
5923
  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
5924
  console.error(`${RED4}${message}${RESET5}`);
5230
5925
  process.exitCode = 1;
5231
5926
  return;
5232
5927
  }
5233
- const tokensCSS = readFileSync14(tokensPath, "utf-8");
5928
+ const tokensCSS = readFileSync15(tokensPath, "utf-8");
5234
5929
  const tokens = parseTokensCSS(tokensCSS);
5235
5930
  if (tokens.size === 0) {
5236
5931
  console.error(`${RED4}No --d-* tokens found in tokens.css.${RESET5}`);
@@ -5242,12 +5937,12 @@ async function cmdExport(target, projectRoot, options = {}) {
5242
5937
  const cssOut = resolveOutputPath(
5243
5938
  projectRoot,
5244
5939
  options.output,
5245
- join19(projectRoot, "src", "styles", "shadcn-theme.css")
5940
+ join20(projectRoot, "src", "styles", "shadcn-theme.css")
5246
5941
  );
5247
- const jsonOut = join19(projectRoot, "components.json");
5942
+ const jsonOut = join20(projectRoot, "components.json");
5248
5943
  ensureDir(cssOut);
5249
- writeFileSync12(cssOut, generateShadcnCSS(tokens), "utf-8");
5250
- writeFileSync12(jsonOut, generateShadcnComponentsJSON(), "utf-8");
5944
+ writeFileSync13(cssOut, generateShadcnCSS(tokens), "utf-8");
5945
+ writeFileSync13(jsonOut, generateShadcnComponentsJSON(), "utf-8");
5251
5946
  console.log(`${GREEN5}Exported shadcn theme:${RESET5}`);
5252
5947
  console.log(` ${DIM5}CSS:${RESET5} ${cssOut}`);
5253
5948
  console.log(` ${DIM5}JSON:${RESET5} ${jsonOut}`);
@@ -5257,10 +5952,10 @@ async function cmdExport(target, projectRoot, options = {}) {
5257
5952
  const out = resolveOutputPath(
5258
5953
  projectRoot,
5259
5954
  options.output,
5260
- join19(projectRoot, "tailwind.decantr.config.ts")
5955
+ join20(projectRoot, "tailwind.decantr.config.ts")
5261
5956
  );
5262
5957
  ensureDir(out);
5263
- writeFileSync12(out, generateTailwindConfig(tokens), "utf-8");
5958
+ writeFileSync13(out, generateTailwindConfig(tokens), "utf-8");
5264
5959
  console.log(`${GREEN5}Exported Tailwind config:${RESET5}`);
5265
5960
  console.log(` ${DIM5}File:${RESET5} ${out}`);
5266
5961
  break;
@@ -5269,10 +5964,10 @@ async function cmdExport(target, projectRoot, options = {}) {
5269
5964
  const out = resolveOutputPath(
5270
5965
  projectRoot,
5271
5966
  options.output,
5272
- join19(projectRoot, "decantr-tokens.css")
5967
+ join20(projectRoot, "decantr-tokens.css")
5273
5968
  );
5274
5969
  ensureDir(out);
5275
- writeFileSync12(out, generateCSSVars(tokens), "utf-8");
5970
+ writeFileSync13(out, generateCSSVars(tokens), "utf-8");
5276
5971
  console.log(`${GREEN5}Exported CSS variables:${RESET5}`);
5277
5972
  console.log(` ${DIM5}File:${RESET5} ${out}`);
5278
5973
  break;
@@ -5281,10 +5976,10 @@ async function cmdExport(target, projectRoot, options = {}) {
5281
5976
  const out = resolveOutputPath(
5282
5977
  projectRoot,
5283
5978
  options.output,
5284
- join19(projectRoot, ".decantr", "design", "figma-tokens.json")
5979
+ join20(projectRoot, ".decantr", "design", "figma-tokens.json")
5285
5980
  );
5286
5981
  ensureDir(out);
5287
- writeFileSync12(out, generateFigmaTokens(tokens), "utf-8");
5982
+ writeFileSync13(out, generateFigmaTokens(tokens), "utf-8");
5288
5983
  console.log(`${GREEN5}Exported Figma/Tokens Studio tokens:${RESET5}`);
5289
5984
  console.log(` ${DIM5}File:${RESET5} ${out}`);
5290
5985
  break;
@@ -5293,15 +5988,15 @@ async function cmdExport(target, projectRoot, options = {}) {
5293
5988
  }
5294
5989
  function ensureDir(filePath) {
5295
5990
  const dir = dirname5(filePath);
5296
- if (!existsSync17(dir)) {
5297
- mkdirSync11(dir, { recursive: true });
5991
+ if (!existsSync18(dir)) {
5992
+ mkdirSync12(dir, { recursive: true });
5298
5993
  }
5299
5994
  }
5300
5995
 
5301
5996
  // src/commands/magic.ts
5302
- import { existsSync as existsSync18 } from "fs";
5997
+ import { existsSync as existsSync19 } from "fs";
5303
5998
  import * as fs from "fs/promises";
5304
- import { join as join20 } from "path";
5999
+ import { join as join21 } from "path";
5305
6000
  var BOLD4 = "\x1B[1m";
5306
6001
  var DIM6 = "\x1B[2m";
5307
6002
  var RESET6 = "\x1B[0m";
@@ -5525,8 +6220,8 @@ async function cmdMagic(prompt, projectRoot, options) {
5525
6220
  console.log(` Archetype: ${intent.archetype}`);
5526
6221
  }
5527
6222
  console.log("");
5528
- const essencePath = join20(projectRoot, "decantr.essence.json");
5529
- if (existsSync18(essencePath)) {
6223
+ const essencePath = join21(projectRoot, "decantr.essence.json");
6224
+ if (existsSync19(essencePath)) {
5530
6225
  const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5531
6226
  console.log(`${YELLOW4} Decantr is already attached to this project.${RESET6}`);
5532
6227
  console.log(
@@ -5559,7 +6254,7 @@ async function cmdMagic(prompt, projectRoot, options) {
5559
6254
  return;
5560
6255
  }
5561
6256
  const registryClient = new RegistryClient({
5562
- cacheDir: join20(projectRoot, ".decantr", "cache"),
6257
+ cacheDir: join21(projectRoot, ".decantr", "cache"),
5563
6258
  apiUrl: options.registry,
5564
6259
  offline: options.offline
5565
6260
  });
@@ -5830,14 +6525,14 @@ async function cmdMagic(prompt, projectRoot, options) {
5830
6525
  if (result.gitignoreUpdated) {
5831
6526
  console.log(` ${dim(".gitignore updated")}`);
5832
6527
  }
5833
- const contextDir = join20(projectRoot, ".decantr", "context");
6528
+ const contextDir = join21(projectRoot, ".decantr", "context");
5834
6529
  let sectionCount = 0;
5835
6530
  try {
5836
6531
  const files = await fs.readdir(contextDir);
5837
6532
  sectionCount = files.filter((f) => f.startsWith("section-")).length;
5838
6533
  } catch {
5839
6534
  }
5840
- const treatmentsPath = join20(projectRoot, "src", "styles", "treatments.css");
6535
+ const treatmentsPath = join21(projectRoot, "src", "styles", "treatments.css");
5841
6536
  let hasLayers = false;
5842
6537
  try {
5843
6538
  const css = await fs.readFile(treatmentsPath, "utf-8");
@@ -5870,8 +6565,8 @@ ${GREEN6}${BOLD4}Quality summary:${RESET6}`);
5870
6565
  }
5871
6566
 
5872
6567
  // 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";
6568
+ import { copyFileSync, existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "fs";
6569
+ import { join as join22 } from "path";
5875
6570
  import {
5876
6571
  isV4 as isV45,
5877
6572
  migrateToV4,
@@ -5884,12 +6579,12 @@ var YELLOW5 = "\x1B[33m";
5884
6579
  var RESET7 = "\x1B[0m";
5885
6580
  var DIM7 = "\x1B[2m";
5886
6581
  function migrateEssenceFile(essencePath) {
5887
- if (!existsSync19(essencePath)) {
6582
+ if (!existsSync20(essencePath)) {
5888
6583
  return { success: false, error: `File not found: ${essencePath}` };
5889
6584
  }
5890
6585
  let raw;
5891
6586
  try {
5892
- raw = readFileSync15(essencePath, "utf-8");
6587
+ raw = readFileSync16(essencePath, "utf-8");
5893
6588
  } catch (e) {
5894
6589
  return { success: false, error: `Could not read ${essencePath}: ${e.message}` };
5895
6590
  }
@@ -5930,7 +6625,7 @@ function migrateEssenceFile(essencePath) {
5930
6625
  };
5931
6626
  }
5932
6627
  try {
5933
- writeFileSync13(essencePath, JSON.stringify(v4, null, 2) + "\n");
6628
+ writeFileSync14(essencePath, JSON.stringify(v4, null, 2) + "\n");
5934
6629
  } catch (e) {
5935
6630
  return {
5936
6631
  success: false,
@@ -5951,8 +6646,8 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5951
6646
  process.exitCode = 1;
5952
6647
  return;
5953
6648
  }
5954
- const essencePath = join21(projectRoot, "decantr.essence.json");
5955
- if (!existsSync19(essencePath)) {
6649
+ const essencePath = join22(projectRoot, "decantr.essence.json");
6650
+ if (!existsSync20(essencePath)) {
5956
6651
  console.error(`${RED5}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5957
6652
  process.exitCode = 1;
5958
6653
  return;
@@ -5974,7 +6669,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5974
6669
  }
5975
6670
  if (result.essence) {
5976
6671
  const registryClient = new RegistryClient({
5977
- cacheDir: join21(projectRoot, ".decantr", "cache")
6672
+ cacheDir: join22(projectRoot, ".decantr", "cache")
5978
6673
  });
5979
6674
  await refreshDerivedFiles(projectRoot, result.essence, registryClient);
5980
6675
  console.log(`${GREEN7}Derived context and execution packs refreshed.${RESET7}`);
@@ -5985,50 +6680,50 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5985
6680
 
5986
6681
  // src/commands/new-project.ts
5987
6682
  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";
6683
+ import { existsSync as existsSync22, mkdirSync as mkdirSync14 } from "fs";
6684
+ import { join as join24, resolve as resolve3 } from "path";
5990
6685
  import { fileURLToPath as fileURLToPath2 } from "url";
5991
6686
 
5992
6687
  // 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";
6688
+ import { cpSync, existsSync as existsSync21, mkdirSync as mkdirSync13 } from "fs";
6689
+ import { join as join23, resolve as resolve2 } from "path";
5995
6690
  var CONTENT_TYPES2 = ["archetypes", "blueprints", "patterns", "themes", "shells"];
5996
6691
  function copyIfExists(source, target) {
5997
- if (!existsSync20(source)) return false;
6692
+ if (!existsSync21(source)) return false;
5998
6693
  if (resolve2(source) === resolve2(target)) return true;
5999
6694
  cpSync(source, target, { recursive: true });
6000
6695
  return true;
6001
6696
  }
6002
6697
  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 });
6698
+ if (!existsSync21(contentRoot)) return false;
6699
+ const customRoot = join23(projectDir, ".decantr", "custom");
6700
+ const cacheRoot = join23(projectDir, ".decantr", "cache", "@official");
6701
+ mkdirSync13(customRoot, { recursive: true });
6702
+ mkdirSync13(cacheRoot, { recursive: true });
6008
6703
  let copiedAny = false;
6009
6704
  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 });
6705
+ const sourceDir = join23(contentRoot, type);
6706
+ if (!existsSync21(sourceDir)) continue;
6707
+ cpSync(sourceDir, join23(customRoot, type), { recursive: true });
6708
+ cpSync(sourceDir, join23(cacheRoot, type), { recursive: true });
6014
6709
  copiedAny = true;
6015
6710
  }
6016
6711
  return copiedAny;
6017
6712
  }
6018
6713
  function seedOfflineRegistry(projectDir, workspaceRoot) {
6019
- const projectDecantrRoot = join22(projectDir, ".decantr");
6020
- mkdirSync12(projectDecantrRoot, { recursive: true });
6714
+ const projectDecantrRoot = join23(projectDir, ".decantr");
6715
+ mkdirSync13(projectDecantrRoot, { recursive: true });
6021
6716
  const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve2(process.env.DECANTR_CONTENT_DIR) : null;
6022
6717
  if (configuredContentRoot && hydrateContentRoot(projectDir, configuredContentRoot)) {
6023
6718
  return { seeded: true, strategy: "configured-content-root" };
6024
6719
  }
6025
6720
  const copiedCache = copyIfExists(
6026
- join22(workspaceRoot, ".decantr", "cache"),
6027
- join22(projectDecantrRoot, "cache")
6721
+ join23(workspaceRoot, ".decantr", "cache"),
6722
+ join23(projectDecantrRoot, "cache")
6028
6723
  );
6029
6724
  const copiedCustom = copyIfExists(
6030
- join22(workspaceRoot, ".decantr", "custom"),
6031
- join22(projectDecantrRoot, "custom")
6725
+ join23(workspaceRoot, ".decantr", "custom"),
6726
+ join23(projectDecantrRoot, "custom")
6032
6727
  );
6033
6728
  if (copiedCache || copiedCustom) {
6034
6729
  return { seeded: true, strategy: "workspace-cache" };
@@ -6141,7 +6836,7 @@ function runArgvCommand(command, args, cwd) {
6141
6836
  }
6142
6837
  function resolveInitCommand(initFlags) {
6143
6838
  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;
6839
+ const cliEntrypoint = existsSync22(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync22(process.argv[1]) ? process.argv[1] : null;
6145
6840
  if (cliEntrypoint) {
6146
6841
  return {
6147
6842
  command: process.execPath,
@@ -6169,7 +6864,7 @@ async function cmdNewProject(projectName, options) {
6169
6864
  process.exitCode = 1;
6170
6865
  return;
6171
6866
  }
6172
- if (existsSync21(projectDir)) {
6867
+ if (existsSync22(projectDir)) {
6173
6868
  console.error(error(`Directory "${projectName}" already exists.`));
6174
6869
  process.exitCode = 1;
6175
6870
  return;
@@ -6183,7 +6878,7 @@ async function cmdNewProject(projectName, options) {
6183
6878
  return;
6184
6879
  }
6185
6880
  console.log(heading(`Creating ${projectName}...`));
6186
- mkdirSync13(projectDir, { recursive: true });
6881
+ mkdirSync14(projectDir, { recursive: true });
6187
6882
  console.log(dim2(` Created ${projectName}/`));
6188
6883
  const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
6189
6884
  if (shouldBootstrapRuntime && bootstrapAdapter) {
@@ -6282,21 +6977,21 @@ ${YELLOW6}Decantr init encountered issues. Run \`decantr init\` manually inside
6282
6977
  }
6283
6978
  }
6284
6979
  function detectPackageManager4() {
6285
- if (existsSync21(join23(process.cwd(), "pnpm-lock.yaml")) || existsSync21(join23(process.cwd(), "pnpm-workspace.yaml"))) {
6980
+ if (existsSync22(join24(process.cwd(), "pnpm-lock.yaml")) || existsSync22(join24(process.cwd(), "pnpm-workspace.yaml"))) {
6286
6981
  return "pnpm";
6287
6982
  }
6288
- if (existsSync21(join23(process.cwd(), "yarn.lock"))) {
6983
+ if (existsSync22(join24(process.cwd(), "yarn.lock"))) {
6289
6984
  return "yarn";
6290
6985
  }
6291
- if (existsSync21(join23(process.cwd(), "bun.lockb")) || existsSync21(join23(process.cwd(), "bun.lock"))) {
6986
+ if (existsSync22(join24(process.cwd(), "bun.lockb")) || existsSync22(join24(process.cwd(), "bun.lock"))) {
6292
6987
  return "bun";
6293
6988
  }
6294
6989
  return "npm";
6295
6990
  }
6296
6991
 
6297
6992
  // src/commands/publish.ts
6298
- import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
6299
- import { join as join24 } from "path";
6993
+ import { existsSync as existsSync23, readFileSync as readFileSync17 } from "fs";
6994
+ import { join as join25 } from "path";
6300
6995
  import {
6301
6996
  API_CONTENT_TYPE_TO_CONTENT_TYPE,
6302
6997
  CONTENT_TYPE_TO_API_CONTENT_TYPE as CONTENT_TYPE_TO_API_CONTENT_TYPE2,
@@ -6312,8 +7007,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
6312
7007
  }
6313
7008
  const singularType = API_CONTENT_TYPE_TO_CONTENT_TYPE[type] || type;
6314
7009
  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)) {
7010
+ const customPath = join25(projectRoot, ".decantr", "custom", pluralType, `${name}.json`);
7011
+ if (!existsSync23(customPath)) {
6317
7012
  console.error(`Custom ${singularType} "${name}" not found at ${customPath}`);
6318
7013
  console.error(`Create one first: decantr create ${singularType} ${name}`);
6319
7014
  process.exitCode = 1;
@@ -6321,7 +7016,7 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
6321
7016
  }
6322
7017
  let data;
6323
7018
  try {
6324
- data = JSON.parse(readFileSync16(customPath, "utf-8"));
7019
+ data = JSON.parse(readFileSync17(customPath, "utf-8"));
6325
7020
  } catch {
6326
7021
  console.error(`Failed to parse ${customPath}`);
6327
7022
  process.exitCode = 1;
@@ -6360,8 +7055,8 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
6360
7055
 
6361
7056
  // src/commands/refresh.ts
6362
7057
  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";
7058
+ import { existsSync as existsSync24, readdirSync as readdirSync7, readFileSync as readFileSync18, statSync as statSync6 } from "fs";
7059
+ import { isAbsolute as isAbsolute2, join as join26, relative as relative6 } from "path";
6365
7060
  import { collectMissingPackManifestFiles as collectMissingPackManifestFiles2 } from "@decantr/verifier";
6366
7061
  import { isV4 as isV46 } from "@decantr/essence-spec";
6367
7062
  var GREEN9 = "\x1B[32m";
@@ -6369,13 +7064,13 @@ var RED7 = "\x1B[31m";
6369
7064
  var DIM9 = "\x1B[2m";
6370
7065
  var RESET9 = "\x1B[0m";
6371
7066
  function hashFile(path) {
6372
- return createHash("sha256").update(readFileSync17(path)).digest("hex");
7067
+ return createHash("sha256").update(readFileSync18(path)).digest("hex");
6373
7068
  }
6374
7069
  function walkFiles(dir) {
6375
- if (!existsSync23(dir)) return [];
7070
+ if (!existsSync24(dir)) return [];
6376
7071
  const files = [];
6377
7072
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
6378
- const path = join25(dir, entry.name);
7073
+ const path = join26(dir, entry.name);
6379
7074
  if (entry.isDirectory()) {
6380
7075
  files.push(...walkFiles(path));
6381
7076
  } else if (entry.isFile()) {
@@ -6386,10 +7081,10 @@ function walkFiles(dir) {
6386
7081
  }
6387
7082
  function trackedGeneratedFiles(projectRoot) {
6388
7083
  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));
7084
+ join26(projectRoot, "DECANTR.md"),
7085
+ ...walkFiles(join26(projectRoot, ".decantr", "context")),
7086
+ ...["global.css", "tokens.css", "treatments.css", "decantr-bridge.css"].map((file) => join26(projectRoot, "src", "styles", file)).filter((path) => existsSync24(path))
7087
+ ].filter((path) => existsSync24(path));
6393
7088
  }
6394
7089
  function snapshotGeneratedFiles(projectRoot) {
6395
7090
  const map = /* @__PURE__ */ new Map();
@@ -6412,33 +7107,33 @@ function fileMtimeMs(path) {
6412
7107
  }
6413
7108
  function newestInputMtime(projectRoot) {
6414
7109
  return Math.max(
6415
- fileMtimeMs(join25(projectRoot, "decantr.essence.json")),
6416
- fileMtimeMs(join25(projectRoot, ".decantr", "project.json"))
7110
+ fileMtimeMs(join26(projectRoot, "decantr.essence.json")),
7111
+ fileMtimeMs(join26(projectRoot, ".decantr", "project.json"))
6417
7112
  );
6418
7113
  }
6419
7114
  function isContractOnlyProject2(projectRoot) {
6420
- const projectJsonPath = join25(projectRoot, ".decantr", "project.json");
6421
- if (!existsSync23(projectJsonPath)) return false;
7115
+ const projectJsonPath = join26(projectRoot, ".decantr", "project.json");
7116
+ if (!existsSync24(projectJsonPath)) return false;
6422
7117
  try {
6423
- const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
7118
+ const projectJson = JSON.parse(readFileSync18(projectJsonPath, "utf-8"));
6424
7119
  return projectJson.initialized?.adoptionMode === "contract-only";
6425
7120
  } catch {
6426
7121
  return false;
6427
7122
  }
6428
7123
  }
6429
7124
  function checkRefreshFreshness(projectRoot) {
6430
- const contextDir = join25(projectRoot, ".decantr", "context");
7125
+ const contextDir = join26(projectRoot, ".decantr", "context");
6431
7126
  const generated = trackedGeneratedFiles(projectRoot);
6432
7127
  const reasons = [];
6433
7128
  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"))) {
7129
+ if (!existsSync24(join26(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
7130
+ if (!existsSync24(contextDir)) reasons.push(".decantr/context is missing.");
7131
+ if (!existsSync24(join26(contextDir, "scaffold.md"))) {
6437
7132
  reasons.push(".decantr/context/scaffold.md is missing.");
6438
7133
  }
6439
- if (!packHydrationOptional && !existsSync23(join25(contextDir, "pack-manifest.json"))) {
7134
+ if (!packHydrationOptional && !existsSync24(join26(contextDir, "pack-manifest.json"))) {
6440
7135
  reasons.push(".decantr/context/pack-manifest.json is missing.");
6441
- } else if (existsSync23(join25(contextDir, "pack-manifest.json"))) {
7136
+ } else if (existsSync24(join26(contextDir, "pack-manifest.json"))) {
6442
7137
  const missingPackFiles = collectMissingPackManifestFiles2(projectRoot);
6443
7138
  if (missingPackFiles.length > 0) {
6444
7139
  reasons.push(
@@ -6491,7 +7186,7 @@ function summarizeChanges(projectRoot, before, after) {
6491
7186
  }
6492
7187
  function displayGeneratedPath(summary, file, displayRoot) {
6493
7188
  if (!displayRoot) return file;
6494
- const absolutePath = join25(summary.projectRoot, file);
7189
+ const absolutePath = join26(summary.projectRoot, file);
6495
7190
  const relativePath = relative6(displayRoot, absolutePath).replace(/\\/g, "/");
6496
7191
  if (relativePath && !relativePath.startsWith("..") && !isAbsolute2(relativePath)) {
6497
7192
  return relativePath;
@@ -6526,15 +7221,15 @@ function printRefreshSummary(summary, displayRoot) {
6526
7221
  }
6527
7222
  }
6528
7223
  async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6529
- const essencePath = join25(projectRoot, "decantr.essence.json");
6530
- if (!existsSync23(essencePath)) {
7224
+ const essencePath = join26(projectRoot, "decantr.essence.json");
7225
+ if (!existsSync24(essencePath)) {
6531
7226
  console.error(`${RED7}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6532
7227
  process.exitCode = 1;
6533
7228
  return;
6534
7229
  }
6535
7230
  let essence;
6536
7231
  try {
6537
- const raw = readFileSync17(essencePath, "utf-8");
7232
+ const raw = readFileSync18(essencePath, "utf-8");
6538
7233
  const parsed = JSON.parse(raw);
6539
7234
  if (!isV46(parsed)) {
6540
7235
  console.error(
@@ -6560,7 +7255,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6560
7255
  return;
6561
7256
  }
6562
7257
  const registryClient = new RegistryClient({
6563
- cacheDir: join25(projectRoot, ".decantr", "cache"),
7258
+ cacheDir: join26(projectRoot, ".decantr", "cache"),
6564
7259
  offline: options.offline
6565
7260
  });
6566
7261
  console.log("Regenerating derived files...\n");
@@ -6591,8 +7286,8 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6591
7286
  }
6592
7287
 
6593
7288
  // src/commands/registry-mirror.ts
6594
- import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync14 } from "fs";
6595
- import { join as join26 } from "path";
7289
+ import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync15 } from "fs";
7290
+ import { join as join27 } from "path";
6596
7291
  import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
6597
7292
  var GREEN10 = "\x1B[32m";
6598
7293
  var RED8 = "\x1B[31m";
@@ -6620,7 +7315,7 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
6620
7315
  process.exitCode = 1;
6621
7316
  return;
6622
7317
  }
6623
- const cacheDir = join26(projectRoot, ".decantr", "cache");
7318
+ const cacheDir = join27(projectRoot, ".decantr", "cache");
6624
7319
  const counts = {};
6625
7320
  const failed = [];
6626
7321
  console.log(`
@@ -6630,19 +7325,19 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6630
7325
  try {
6631
7326
  const result = await apiClient.listContent(type, { namespace: "@official" });
6632
7327
  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));
7328
+ const typeDir = join27(cacheDir, "@official", type);
7329
+ mkdirSync15(typeDir, { recursive: true });
7330
+ writeFileSync15(join27(typeDir, "index.json"), JSON.stringify(result, null, 2));
6636
7331
  let itemCount = 0;
6637
7332
  for (const item of items) {
6638
7333
  const slug = item.slug || item.id;
6639
7334
  if (!slug) continue;
6640
7335
  try {
6641
7336
  const fullItem = await apiClient.getContent(type, "@official", slug);
6642
- writeFileSync14(join26(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
7337
+ writeFileSync15(join27(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
6643
7338
  itemCount++;
6644
7339
  } catch {
6645
- writeFileSync14(join26(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
7340
+ writeFileSync15(join27(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
6646
7341
  itemCount++;
6647
7342
  }
6648
7343
  }
@@ -6657,8 +7352,8 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6657
7352
  mirrored_at: (/* @__PURE__ */ new Date()).toISOString(),
6658
7353
  counts
6659
7354
  };
6660
- mkdirSync14(join26(cacheDir), { recursive: true });
6661
- writeFileSync14(join26(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
7355
+ mkdirSync15(join27(cacheDir), { recursive: true });
7356
+ writeFileSync15(join27(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
6662
7357
  const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
6663
7358
  console.log("");
6664
7359
  if (failed.length > 0) {
@@ -6675,8 +7370,8 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6675
7370
  }
6676
7371
 
6677
7372
  // 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";
7373
+ import { existsSync as existsSync26, readFileSync as readFileSync19, rmSync as rmSync2, writeFileSync as writeFileSync16 } from "fs";
7374
+ import { join as join28 } from "path";
6680
7375
  import { isV4 as isV47 } from "@decantr/essence-spec";
6681
7376
  var GREEN11 = "\x1B[32m";
6682
7377
  var RED9 = "\x1B[31m";
@@ -6684,15 +7379,15 @@ var YELLOW8 = "\x1B[33m";
6684
7379
  var DIM11 = "\x1B[2m";
6685
7380
  var RESET11 = "\x1B[0m";
6686
7381
  function readV4Essence2(projectRoot) {
6687
- const essencePath = join27(projectRoot, "decantr.essence.json");
6688
- if (!existsSync25(essencePath)) {
7382
+ const essencePath = join28(projectRoot, "decantr.essence.json");
7383
+ if (!existsSync26(essencePath)) {
6689
7384
  console.error(`${RED9}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6690
7385
  process.exitCode = 1;
6691
7386
  return null;
6692
7387
  }
6693
7388
  let parsed;
6694
7389
  try {
6695
- parsed = JSON.parse(readFileSync18(essencePath, "utf-8"));
7390
+ parsed = JSON.parse(readFileSync19(essencePath, "utf-8"));
6696
7391
  } catch (e) {
6697
7392
  console.error(`${RED9}Could not read essence: ${e.message}${RESET11}`);
6698
7393
  process.exitCode = 1;
@@ -6708,7 +7403,7 @@ function readV4Essence2(projectRoot) {
6708
7403
  return { essence: parsed, essencePath };
6709
7404
  }
6710
7405
  function writeEssence2(essencePath, essence) {
6711
- writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n");
7406
+ writeFileSync16(essencePath, JSON.stringify(essence, null, 2) + "\n");
6712
7407
  }
6713
7408
  function readFlagValue2(args, name) {
6714
7409
  const prefix = `--${name}=`;
@@ -6780,14 +7475,14 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6780
7475
  sections.splice(idx, 1);
6781
7476
  recomputeGlobalFeatures(essence);
6782
7477
  removeRoutes(essence, sectionId);
6783
- const contextFile = join27(projectRoot, ".decantr", "context", `${sectionId}.md`);
6784
- if (existsSync25(contextFile)) {
7478
+ const contextFile = join28(projectRoot, ".decantr", "context", `${sectionId}.md`);
7479
+ if (existsSync26(contextFile)) {
6785
7480
  rmSync2(contextFile);
6786
7481
  }
6787
7482
  writeEssence2(essencePath, essence);
6788
7483
  console.log(`${GREEN11}Removed section "${sectionId}".${RESET11}`);
6789
7484
  const registryClient = new RegistryClient({
6790
- cacheDir: join27(projectRoot, ".decantr", "cache")
7485
+ cacheDir: join28(projectRoot, ".decantr", "cache")
6791
7486
  });
6792
7487
  await refreshDerivedFiles(projectRoot, essence, registryClient);
6793
7488
  console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
@@ -6830,7 +7525,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6830
7525
  }
6831
7526
  console.log(`${GREEN11}Removed page "${pageId}" from section "${resolvedSectionId}".${RESET11}`);
6832
7527
  const registryClient = new RegistryClient({
6833
- cacheDir: join27(projectRoot, ".decantr", "cache")
7528
+ cacheDir: join28(projectRoot, ".decantr", "cache")
6834
7529
  });
6835
7530
  await refreshDerivedFiles(projectRoot, essence, registryClient);
6836
7531
  console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
@@ -6873,15 +7568,15 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6873
7568
  const target = sectionId ? `section "${sectionId}" and global` : "global";
6874
7569
  console.log(`${GREEN11}Removed feature "${feature}" from ${target} features.${RESET11}`);
6875
7570
  const registryClient = new RegistryClient({
6876
- cacheDir: join27(projectRoot, ".decantr", "cache")
7571
+ cacheDir: join28(projectRoot, ".decantr", "cache")
6877
7572
  });
6878
7573
  await refreshDerivedFiles(projectRoot, essence, registryClient);
6879
7574
  console.log(`${GREEN11}Derived files refreshed.${RESET11}`);
6880
7575
  }
6881
7576
 
6882
7577
  // 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";
7578
+ import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "fs";
7579
+ import { join as join29 } from "path";
6885
7580
  var GREEN12 = "\x1B[32m";
6886
7581
  var RED10 = "\x1B[31m";
6887
7582
  var YELLOW9 = "\x1B[33m";
@@ -6890,8 +7585,8 @@ var DIM12 = "\x1B[2m";
6890
7585
  var BOLD6 = "\x1B[1m";
6891
7586
  var CYAN6 = "\x1B[36m";
6892
7587
  async function cmdSyncDrift(projectRoot = process.cwd()) {
6893
- const driftLogPath = join28(projectRoot, ".decantr", "drift-log.json");
6894
- if (!existsSync26(driftLogPath)) {
7588
+ const driftLogPath = join29(projectRoot, ".decantr", "drift-log.json");
7589
+ if (!existsSync27(driftLogPath)) {
6895
7590
  console.log(`${GREEN12}No drift log found \u2014 no drift recorded.${RESET12}`);
6896
7591
  console.log(
6897
7592
  `${DIM12}Drift is logged when guard violations are detected during development.${RESET12}`
@@ -6900,7 +7595,7 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
6900
7595
  }
6901
7596
  let entries;
6902
7597
  try {
6903
- entries = JSON.parse(readFileSync19(driftLogPath, "utf-8"));
7598
+ entries = JSON.parse(readFileSync20(driftLogPath, "utf-8"));
6904
7599
  } catch {
6905
7600
  console.error(`${RED10}Could not parse drift-log.json${RESET12}`);
6906
7601
  process.exitCode = 1;
@@ -6946,13 +7641,13 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6946
7641
  console.log("");
6947
7642
  }
6948
7643
  function resolveDriftEntries(projectRoot, options) {
6949
- const driftLogPath = join28(projectRoot, ".decantr", "drift-log.json");
6950
- if (!existsSync26(driftLogPath)) {
7644
+ const driftLogPath = join29(projectRoot, ".decantr", "drift-log.json");
7645
+ if (!existsSync27(driftLogPath)) {
6951
7646
  return { success: true };
6952
7647
  }
6953
7648
  if (options.clear) {
6954
7649
  try {
6955
- writeFileSync16(driftLogPath, "[]");
7650
+ writeFileSync17(driftLogPath, "[]");
6956
7651
  return { success: true };
6957
7652
  } catch (e) {
6958
7653
  return { success: false, error: `Could not clear drift log: ${e.message}` };
@@ -6960,7 +7655,7 @@ function resolveDriftEntries(projectRoot, options) {
6960
7655
  }
6961
7656
  let entries;
6962
7657
  try {
6963
- entries = JSON.parse(readFileSync19(driftLogPath, "utf-8"));
7658
+ entries = JSON.parse(readFileSync20(driftLogPath, "utf-8"));
6964
7659
  } catch {
6965
7660
  return { success: false, error: "Could not parse drift-log.json" };
6966
7661
  }
@@ -6979,7 +7674,7 @@ function resolveDriftEntries(projectRoot, options) {
6979
7674
  }
6980
7675
  }
6981
7676
  try {
6982
- writeFileSync16(driftLogPath, JSON.stringify(entries, null, 2));
7677
+ writeFileSync17(driftLogPath, JSON.stringify(entries, null, 2));
6983
7678
  return { success: true };
6984
7679
  } catch (e) {
6985
7680
  return { success: false, error: `Could not write drift log: ${e.message}` };
@@ -7204,8 +7899,8 @@ function trimTrailingSlashes(value) {
7204
7899
  }
7205
7900
 
7206
7901
  // 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";
7902
+ import { existsSync as existsSync28, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
7903
+ import { join as join30 } from "path";
7209
7904
  import { isV4 as isV48 } from "@decantr/essence-spec";
7210
7905
  var GREEN14 = "\x1B[32m";
7211
7906
  var RED11 = "\x1B[31m";
@@ -7222,15 +7917,15 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
7222
7917
  process.exitCode = 1;
7223
7918
  return;
7224
7919
  }
7225
- const essencePath = join29(projectRoot, "decantr.essence.json");
7226
- if (!existsSync27(essencePath)) {
7920
+ const essencePath = join30(projectRoot, "decantr.essence.json");
7921
+ if (!existsSync28(essencePath)) {
7227
7922
  console.error(`${RED11}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
7228
7923
  process.exitCode = 1;
7229
7924
  return;
7230
7925
  }
7231
7926
  let parsed;
7232
7927
  try {
7233
- parsed = JSON.parse(readFileSync20(essencePath, "utf-8"));
7928
+ parsed = JSON.parse(readFileSync21(essencePath, "utf-8"));
7234
7929
  } catch (e) {
7235
7930
  console.error(`${RED11}Could not read essence: ${e.message}${RESET14}`);
7236
7931
  process.exitCode = 1;
@@ -7281,7 +7976,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
7281
7976
  essence.dna.theme.mode = mode;
7282
7977
  }
7283
7978
  const registryClient = new RegistryClient({
7284
- cacheDir: join29(projectRoot, ".decantr", "cache")
7979
+ cacheDir: join30(projectRoot, ".decantr", "cache")
7285
7980
  });
7286
7981
  try {
7287
7982
  const themeResult = await registryClient.fetchTheme(themeName);
@@ -7296,7 +7991,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
7296
7991
  }
7297
7992
  } catch {
7298
7993
  }
7299
- writeFileSync17(essencePath, JSON.stringify(essence, null, 2) + "\n");
7994
+ writeFileSync18(essencePath, JSON.stringify(essence, null, 2) + "\n");
7300
7995
  console.log(`${GREEN14}Switched theme: ${oldThemeId} \u2192 ${themeName}${RESET14}`);
7301
7996
  if (shape) console.log(` ${DIM14}Shape: ${shape}${RESET14}`);
7302
7997
  if (mode) console.log(` ${DIM14}Mode: ${mode}${RESET14}`);
@@ -7604,8 +8299,8 @@ async function runSimplifiedInit(blueprints) {
7604
8299
  }
7605
8300
 
7606
8301
  // 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";
8302
+ import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync8, readFileSync as readFileSync22, rmSync as rmSync3, writeFileSync as writeFileSync19 } from "fs";
8303
+ import { join as join31 } from "path";
7609
8304
  var REQUIRED_FIELDS = [
7610
8305
  "$schema",
7611
8306
  "id",
@@ -7665,20 +8360,20 @@ function validateCustomTheme(theme) {
7665
8360
  };
7666
8361
  }
7667
8362
  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)) {
8363
+ const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
8364
+ const themePath = join31(customThemesDir, `${id}.json`);
8365
+ const howToPath = join31(customThemesDir, "how-to-theme.md");
8366
+ mkdirSync16(customThemesDir, { recursive: true });
8367
+ if (existsSync29(themePath)) {
7673
8368
  return {
7674
8369
  success: false,
7675
8370
  error: `Theme "${id}" already exists at ${themePath}`
7676
8371
  };
7677
8372
  }
7678
8373
  const skeleton = getThemeSkeleton(id, name);
7679
- writeFileSync18(themePath, JSON.stringify(skeleton, null, 2));
7680
- if (!existsSync28(howToPath)) {
7681
- writeFileSync18(howToPath, getHowToThemeDoc());
8374
+ writeFileSync19(themePath, JSON.stringify(skeleton, null, 2));
8375
+ if (!existsSync29(howToPath)) {
8376
+ writeFileSync19(howToPath, getHowToThemeDoc());
7682
8377
  }
7683
8378
  return {
7684
8379
  success: true,
@@ -7686,17 +8381,17 @@ function createTheme(projectRoot, id, name) {
7686
8381
  };
7687
8382
  }
7688
8383
  function listCustomThemes(projectRoot) {
7689
- const customThemesDir = join30(projectRoot, ".decantr", "custom", "themes");
7690
- if (!existsSync28(customThemesDir)) {
8384
+ const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
8385
+ if (!existsSync29(customThemesDir)) {
7691
8386
  return [];
7692
8387
  }
7693
8388
  const themes = [];
7694
8389
  try {
7695
8390
  const files = readdirSync8(customThemesDir).filter((f) => f.endsWith(".json"));
7696
8391
  for (const file of files) {
7697
- const filePath = join30(customThemesDir, file);
8392
+ const filePath = join31(customThemesDir, file);
7698
8393
  try {
7699
- const data = JSON.parse(readFileSync21(filePath, "utf-8"));
8394
+ const data = JSON.parse(readFileSync22(filePath, "utf-8"));
7700
8395
  themes.push({
7701
8396
  id: data.id || file.replace(".json", ""),
7702
8397
  name: data.name || data.id,
@@ -7711,8 +8406,8 @@ function listCustomThemes(projectRoot) {
7711
8406
  return themes;
7712
8407
  }
7713
8408
  function deleteTheme(projectRoot, id) {
7714
- const themePath = join30(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
7715
- if (!existsSync28(themePath)) {
8409
+ const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${id}.json`);
8410
+ if (!existsSync29(themePath)) {
7716
8411
  return {
7717
8412
  success: false,
7718
8413
  error: `Theme "${id}" not found at ${themePath}`
@@ -7729,7 +8424,7 @@ function deleteTheme(projectRoot, id) {
7729
8424
  }
7730
8425
  }
7731
8426
  function importTheme(projectRoot, sourcePath) {
7732
- if (!existsSync28(sourcePath)) {
8427
+ if (!existsSync29(sourcePath)) {
7733
8428
  return {
7734
8429
  success: false,
7735
8430
  errors: [`Source file not found: ${sourcePath}`]
@@ -7737,7 +8432,7 @@ function importTheme(projectRoot, sourcePath) {
7737
8432
  }
7738
8433
  let theme;
7739
8434
  try {
7740
- theme = JSON.parse(readFileSync21(sourcePath, "utf-8"));
8435
+ theme = JSON.parse(readFileSync22(sourcePath, "utf-8"));
7741
8436
  } catch (e) {
7742
8437
  return {
7743
8438
  success: false,
@@ -7753,14 +8448,14 @@ function importTheme(projectRoot, sourcePath) {
7753
8448
  }
7754
8449
  theme.source = "custom";
7755
8450
  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));
8451
+ const customThemesDir = join31(projectRoot, ".decantr", "custom", "themes");
8452
+ const destPath = join31(customThemesDir, `${id}.json`);
8453
+ mkdirSync16(customThemesDir, { recursive: true });
8454
+ const howToPath = join31(customThemesDir, "how-to-theme.md");
8455
+ if (!existsSync29(howToPath)) {
8456
+ writeFileSync19(howToPath, getHowToThemeDoc());
8457
+ }
8458
+ writeFileSync19(destPath, JSON.stringify(theme, null, 2));
7764
8459
  return {
7765
8460
  success: true,
7766
8461
  path: destPath
@@ -8307,18 +9002,18 @@ function extractHostedAssetPaths(indexHtml) {
8307
9002
  return [...assetPaths];
8308
9003
  }
8309
9004
  function readHostedDistSnapshot(distPath) {
8310
- const resolvedDistPath = distPath ? resolveUserPath(distPath) : join31(process.cwd(), "dist");
8311
- const indexPath = join31(resolvedDistPath, "index.html");
8312
- if (!existsSync29(indexPath)) {
9005
+ const resolvedDistPath = distPath ? resolveUserPath(distPath) : join32(process.cwd(), "dist");
9006
+ const indexPath = join32(resolvedDistPath, "index.html");
9007
+ if (!existsSync30(indexPath)) {
8313
9008
  return void 0;
8314
9009
  }
8315
- const indexHtml = readFileSync22(indexPath, "utf-8");
9010
+ const indexHtml = readFileSync23(indexPath, "utf-8");
8316
9011
  const assetPaths = extractHostedAssetPaths(indexHtml);
8317
9012
  const assets = {};
8318
9013
  for (const assetPath of assetPaths) {
8319
- const assetFilePath = join31(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
8320
- if (existsSync29(assetFilePath)) {
8321
- assets[assetPath] = readFileSync22(assetFilePath, "utf-8");
9014
+ const assetFilePath = join32(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
9015
+ if (existsSync30(assetFilePath)) {
9016
+ assets[assetPath] = readFileSync23(assetFilePath, "utf-8");
8322
9017
  }
8323
9018
  }
8324
9019
  return {
@@ -8333,7 +9028,7 @@ function isHostedSourceSnapshotFile(path) {
8333
9028
  function readHostedSourceSnapshot(sourcePath) {
8334
9029
  if (!sourcePath) return void 0;
8335
9030
  const resolvedSourcePath = resolveUserPath(sourcePath);
8336
- if (!existsSync29(resolvedSourcePath)) {
9031
+ if (!existsSync30(resolvedSourcePath)) {
8337
9032
  return void 0;
8338
9033
  }
8339
9034
  const files = {};
@@ -8349,15 +9044,15 @@ function readHostedSourceSnapshot(sourcePath) {
8349
9044
  const walk = (absoluteDir, relativeDir) => {
8350
9045
  for (const entry of readdirSync9(absoluteDir, { withFileTypes: true })) {
8351
9046
  if (ignoredDirNames.has(entry.name)) continue;
8352
- const absolutePath = join31(absoluteDir, entry.name);
8353
- const relativePath = join31(relativeDir, entry.name).replace(/\\/g, "/");
9047
+ const absolutePath = join32(absoluteDir, entry.name);
9048
+ const relativePath = join32(relativeDir, entry.name).replace(/\\/g, "/");
8354
9049
  if (entry.isDirectory()) {
8355
9050
  walk(absolutePath, relativePath);
8356
9051
  continue;
8357
9052
  }
8358
9053
  if (!entry.isFile()) continue;
8359
9054
  if (!isHostedSourceSnapshotFile(relativePath)) continue;
8360
- files[relativePath] = readFileSync22(absolutePath, "utf-8");
9055
+ files[relativePath] = readFileSync23(absolutePath, "utf-8");
8361
9056
  }
8362
9057
  };
8363
9058
  walk(resolvedSourcePath, rootPrefix);
@@ -8550,24 +9245,24 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
8550
9245
  }
8551
9246
  async function compileHostedExecutionPackBundle(essencePath, namespace) {
8552
9247
  const client = getPublicAPIClient();
8553
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
8554
- if (!existsSync29(resolvedPath)) {
9248
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
9249
+ if (!existsSync30(resolvedPath)) {
8555
9250
  throw new Error(`Essence file not found at ${resolvedPath}`);
8556
9251
  }
8557
- const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
9252
+ const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
8558
9253
  const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
8559
- const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
9254
+ const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
8560
9255
  return { resolvedPath, bundle, contextDir };
8561
9256
  }
8562
9257
  function writeHostedExecutionPackContextArtifacts(contextDir, bundle) {
8563
- mkdirSync16(contextDir, { recursive: true });
9258
+ mkdirSync17(contextDir, { recursive: true });
8564
9259
  return writeExecutionPackBundleArtifacts(contextDir, bundle);
8565
9260
  }
8566
9261
  function resolvePagePackIdForRoute(essencePath, route) {
8567
- if (!existsSync29(essencePath)) {
9262
+ if (!existsSync30(essencePath)) {
8568
9263
  throw new Error(`Essence file not found at ${essencePath}`);
8569
9264
  }
8570
- const essence = JSON.parse(readFileSync22(essencePath, "utf-8"));
9265
+ const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
8571
9266
  if (!isV49(essence)) {
8572
9267
  throw new Error("Route-based pack resolution requires Essence v4.0.0.");
8573
9268
  }
@@ -8582,14 +9277,14 @@ function resolvePagePackIdForRoute(essencePath, route) {
8582
9277
  }
8583
9278
  async function printHostedSelectedExecutionPack(packType, id, essencePath, namespace, jsonOutput = false, writeContext = false) {
8584
9279
  const client = getPublicAPIClient();
8585
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
8586
- if (!existsSync29(resolvedPath)) {
9280
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
9281
+ if (!existsSync30(resolvedPath)) {
8587
9282
  throw new Error(`Essence file not found at ${resolvedPath}`);
8588
9283
  }
8589
9284
  if ((packType === "section" || packType === "page" || packType === "mutation") && !id) {
8590
9285
  throw new Error(`Pack type "${packType}" requires an id.`);
8591
9286
  }
8592
- const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
9287
+ const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
8593
9288
  const selected = await client.selectExecutionPack(
8594
9289
  {
8595
9290
  essence,
@@ -8600,17 +9295,17 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
8600
9295
  );
8601
9296
  let writtenContextDir = null;
8602
9297
  if (writeContext) {
8603
- const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
8604
- mkdirSync16(contextDir, { recursive: true });
8605
- writeFileSync19(
8606
- join31(contextDir, "pack-manifest.json"),
9298
+ const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
9299
+ mkdirSync17(contextDir, { recursive: true });
9300
+ writeFileSync20(
9301
+ join32(contextDir, "pack-manifest.json"),
8607
9302
  JSON.stringify(selected.manifest, null, 2) + "\n"
8608
9303
  );
8609
9304
  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
9305
  const markdownFile = manifestEntry?.markdown ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.md`;
8611
9306
  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");
9307
+ writeFileSync20(join32(contextDir, markdownFile), selected.pack.renderedMarkdown);
9308
+ writeFileSync20(join32(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
8614
9309
  writtenContextDir = contextDir;
8615
9310
  }
8616
9311
  if (jsonOutput) {
@@ -8635,20 +9330,20 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
8635
9330
  }
8636
9331
  async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutput = false, writeContext = false) {
8637
9332
  const client = getPublicAPIClient();
8638
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
8639
- if (!existsSync29(resolvedPath)) {
9333
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
9334
+ if (!existsSync30(resolvedPath)) {
8640
9335
  throw new Error(`Essence file not found at ${resolvedPath}`);
8641
9336
  }
8642
- const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
9337
+ const essence = JSON.parse(readFileSync23(resolvedPath, "utf-8"));
8643
9338
  const manifest = await client.getExecutionPackManifest(
8644
9339
  essence,
8645
9340
  namespace ? { namespace } : void 0
8646
9341
  );
8647
9342
  let writtenContextDir = null;
8648
9343
  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");
9344
+ const contextDir = join32(dirname6(resolvedPath), ".decantr", "context");
9345
+ mkdirSync17(contextDir, { recursive: true });
9346
+ writeFileSync20(join32(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
8652
9347
  writtenContextDir = contextDir;
8653
9348
  }
8654
9349
  if (jsonOutput) {
@@ -8669,14 +9364,14 @@ async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutp
8669
9364
  }
8670
9365
  }
8671
9366
  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)) {
9367
+ const contextDir = join32(projectRoot, ".decantr", "context");
9368
+ const reviewPackPath = join32(contextDir, "review-pack.json");
9369
+ const manifestPath = join32(contextDir, "pack-manifest.json");
9370
+ if (existsSync30(reviewPackPath) && existsSync30(manifestPath)) {
8676
9371
  return { attempted: false, hydrated: false };
8677
9372
  }
8678
- const essencePath = join31(projectRoot, "decantr.essence.json");
8679
- if (!existsSync29(essencePath)) {
9373
+ const essencePath = join32(projectRoot, "decantr.essence.json");
9374
+ if (!existsSync30(essencePath)) {
8680
9375
  return { attempted: false, hydrated: false };
8681
9376
  }
8682
9377
  const reviewHydration = await hydrateHostedReviewPackIfMissing(projectRoot, namespace);
@@ -8685,9 +9380,9 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
8685
9380
  }
8686
9381
  try {
8687
9382
  const client = getPublicAPIClient();
8688
- const essence = JSON.parse(readFileSync22(essencePath, "utf-8"));
9383
+ const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
8689
9384
  const bundle = await client.compileExecutionPacks(essence, { namespace });
8690
- mkdirSync16(contextDir, { recursive: true });
9385
+ mkdirSync17(contextDir, { recursive: true });
8691
9386
  writeExecutionPackBundleArtifacts(contextDir, bundle);
8692
9387
  return { attempted: true, hydrated: true, scope: "bundle" };
8693
9388
  } catch {
@@ -8695,19 +9390,19 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
8695
9390
  }
8696
9391
  }
8697
9392
  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)) {
9393
+ const contextDir = join32(projectRoot, ".decantr", "context");
9394
+ const reviewPackPath = join32(contextDir, "review-pack.json");
9395
+ const manifestPath = join32(contextDir, "pack-manifest.json");
9396
+ if (existsSync30(reviewPackPath) && existsSync30(manifestPath)) {
8702
9397
  return { attempted: false, hydrated: false };
8703
9398
  }
8704
- const essencePath = join31(projectRoot, "decantr.essence.json");
8705
- if (!existsSync29(essencePath)) {
9399
+ const essencePath = join32(projectRoot, "decantr.essence.json");
9400
+ if (!existsSync30(essencePath)) {
8706
9401
  return { attempted: false, hydrated: false };
8707
9402
  }
8708
9403
  try {
8709
9404
  const client = getPublicAPIClient();
8710
- const essence = JSON.parse(readFileSync22(essencePath, "utf-8"));
9405
+ const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
8711
9406
  const selected = await client.selectExecutionPack(
8712
9407
  {
8713
9408
  essence,
@@ -8715,14 +9410,14 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
8715
9410
  },
8716
9411
  { namespace }
8717
9412
  );
8718
- mkdirSync16(contextDir, { recursive: true });
8719
- writeFileSync19(join31(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
8720
- writeFileSync19(
8721
- join31(contextDir, "review-pack.json"),
9413
+ mkdirSync17(contextDir, { recursive: true });
9414
+ writeFileSync20(join32(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
9415
+ writeFileSync20(
9416
+ join32(contextDir, "review-pack.json"),
8722
9417
  JSON.stringify(selected.pack, null, 2) + "\n"
8723
9418
  );
8724
- if (!existsSync29(manifestPath)) {
8725
- writeFileSync19(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
9419
+ if (!existsSync30(manifestPath)) {
9420
+ writeFileSync20(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
8726
9421
  }
8727
9422
  return { attempted: true, hydrated: true, scope: "review" };
8728
9423
  } catch {
@@ -8732,17 +9427,17 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
8732
9427
  async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false, essencePath, treatmentsPath) {
8733
9428
  const client = getPublicAPIClient();
8734
9429
  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)) {
9430
+ const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
9431
+ const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join32(process.cwd(), "src", "styles", "treatments.css");
9432
+ if (!existsSync30(resolvedSourcePath)) {
8738
9433
  throw new Error(`Source file not found at ${resolvedSourcePath}`);
8739
9434
  }
8740
- if (!existsSync29(resolvedEssencePath)) {
9435
+ if (!existsSync30(resolvedEssencePath)) {
8741
9436
  throw new Error(`Essence file not found at ${resolvedEssencePath}`);
8742
9437
  }
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;
9438
+ const code = readFileSync23(resolvedSourcePath, "utf-8");
9439
+ const essence = JSON.parse(readFileSync23(resolvedEssencePath, "utf-8"));
9440
+ const treatmentsCss = existsSync30(resolvedTreatmentsPath) ? readFileSync23(resolvedTreatmentsPath, "utf-8") : void 0;
8746
9441
  const report = await client.critiqueFile(
8747
9442
  {
8748
9443
  essence,
@@ -8766,11 +9461,11 @@ async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false
8766
9461
  }
8767
9462
  async function printHostedProjectAudit(namespace, jsonOutput = false, essencePath, distPath, sourcesPath) {
8768
9463
  const client = getPublicAPIClient();
8769
- const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
8770
- if (!existsSync29(resolvedEssencePath)) {
9464
+ const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
9465
+ if (!existsSync30(resolvedEssencePath)) {
8771
9466
  throw new Error(`Essence file not found at ${resolvedEssencePath}`);
8772
9467
  }
8773
- const essence = JSON.parse(readFileSync22(resolvedEssencePath, "utf-8"));
9468
+ const essence = JSON.parse(readFileSync23(resolvedEssencePath, "utf-8"));
8774
9469
  const dist = readHostedDistSnapshot(distPath);
8775
9470
  const sources = readHostedSourceSnapshot(sourcesPath);
8776
9471
  const report = await client.auditProject(
@@ -8788,7 +9483,7 @@ async function printHostedProjectAudit(namespace, jsonOutput = false, essencePat
8788
9483
  console.log(heading2("Hosted Project Audit"));
8789
9484
  console.log(` Essence: ${resolvedEssencePath}`);
8790
9485
  console.log(
8791
- ` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join31(process.cwd(), "dist") : "none"}`
9486
+ ` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join32(process.cwd(), "dist") : "none"}`
8792
9487
  );
8793
9488
  console.log(
8794
9489
  ` Source snapshot: ${sources && sourcesPath ? resolveUserPath(sourcesPath) : "none"}`
@@ -8888,24 +9583,43 @@ function patternCandidateFromRegistryItem(item, source) {
8888
9583
  { source, slug }
8889
9584
  );
8890
9585
  }
9586
+ function hostedPatternRefFromCandidate(candidate) {
9587
+ const slug = candidate.slug || candidate.id;
9588
+ return {
9589
+ slug,
9590
+ source: candidate.source ?? "registry",
9591
+ name: candidate.name,
9592
+ description: candidate.description,
9593
+ tags: candidate.tags,
9594
+ components: candidate.components,
9595
+ interactions: candidate.interactions,
9596
+ visualBrief: candidate.visual_brief
9597
+ };
9598
+ }
9599
+ function findPatternCandidateBySlug(candidates, slug) {
9600
+ const normalized = slug.toLowerCase();
9601
+ return candidates.find(
9602
+ (candidate) => candidate.slug?.toLowerCase() === normalized || candidate.id.toLowerCase() === normalized || candidate.name?.toLowerCase() === normalized
9603
+ ) ?? null;
9604
+ }
8891
9605
  function readSuggestCodeContext(projectRoot, route, file) {
8892
9606
  const pieces = [];
8893
9607
  if (file) {
8894
- const resolved = isAbsolute3(file) ? file : join31(projectRoot, file);
8895
- if (existsSync29(resolved)) {
8896
- pieces.push(readFileSync22(resolved, "utf-8"));
9608
+ const resolved = isAbsolute3(file) ? file : join32(projectRoot, file);
9609
+ if (existsSync30(resolved)) {
9610
+ pieces.push(readFileSync23(resolved, "utf-8"));
8897
9611
  }
8898
9612
  }
8899
9613
  if (route) {
8900
- const analysisPath = join31(projectRoot, ".decantr", "analysis.json");
8901
- if (existsSync29(analysisPath)) {
9614
+ const analysisPath = join32(projectRoot, ".decantr", "analysis.json");
9615
+ if (existsSync30(analysisPath)) {
8902
9616
  try {
8903
- const analysis = JSON.parse(readFileSync22(analysisPath, "utf-8"));
9617
+ const analysis = JSON.parse(readFileSync23(analysisPath, "utf-8"));
8904
9618
  const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
8905
9619
  if (routeEntry?.file) {
8906
- const resolved = join31(projectRoot, routeEntry.file);
8907
- if (existsSync29(resolved)) {
8908
- pieces.push(readFileSync22(resolved, "utf-8"));
9620
+ const resolved = join32(projectRoot, routeEntry.file);
9621
+ if (existsSync30(resolved)) {
9622
+ pieces.push(readFileSync23(resolved, "utf-8"));
8909
9623
  }
8910
9624
  }
8911
9625
  } catch {
@@ -8989,10 +9703,11 @@ async function cmdSuggest(query, options = {}) {
8989
9703
  }
8990
9704
  }
8991
9705
  const registryClient = new RegistryClient({
8992
- cacheDir: join31(projectRoot, ".decantr", "cache")
9706
+ cacheDir: join32(projectRoot, ".decantr", "cache")
8993
9707
  });
8994
9708
  const code = options.fromCode || options.file ? readSuggestCodeContext(projectRoot, options.route, options.file) : "";
8995
9709
  const localMatches = localPatternMatches(projectRoot, [query, code].filter(Boolean).join("\n"));
9710
+ const bridgeMatches = styleBridgeMatches(projectRoot, [query, code].filter(Boolean).join("\n"));
8996
9711
  const candidates = await loadPatternDiscoveryCandidates(registryClient);
8997
9712
  const matches = rankPatternCandidates(
8998
9713
  {
@@ -9003,7 +9718,7 @@ async function cmdSuggest(query, options = {}) {
9003
9718
  },
9004
9719
  candidates
9005
9720
  );
9006
- if (matches.length === 0 && localMatches.length === 0) {
9721
+ if (matches.length === 0 && localMatches.length === 0 && bridgeMatches.length === 0) {
9007
9722
  console.log(dim3(`No pattern suggestions for "${query}"`));
9008
9723
  console.log("");
9009
9724
  console.log("Try:");
@@ -9023,6 +9738,14 @@ async function cmdSuggest(query, options = {}) {
9023
9738
  `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
9024
9739
  )
9025
9740
  );
9741
+ if (bridgeMatches.length > 0) {
9742
+ console.log(`${BOLD9}Project-owned style bridge:${RESET16}`);
9743
+ for (const match of bridgeMatches) {
9744
+ const hints = [...match.tokenHints, ...match.classHints].slice(0, 3).join(", ");
9745
+ console.log(` ${cyan3(match.id)} ${match.label}${hints ? ` ${dim3(hints)}` : ""}`);
9746
+ }
9747
+ console.log("");
9748
+ }
9026
9749
  if (localMatches.length > 0) {
9027
9750
  console.log(`${BOLD9}Project-owned local law:${RESET16}`);
9028
9751
  for (const match of localMatches) {
@@ -9067,7 +9790,7 @@ async function cmdGet(type, id) {
9067
9790
  }
9068
9791
  const apiType = CONTENT_TYPE_TO_API_CONTENT_TYPE3[type];
9069
9792
  const registryClient = new RegistryClient({
9070
- cacheDir: join31(process.cwd(), ".decantr", "cache")
9793
+ cacheDir: join32(process.cwd(), ".decantr", "cache")
9071
9794
  });
9072
9795
  const result = await registryClient.fetchContentItem(apiType, id);
9073
9796
  if (result) {
@@ -9084,10 +9807,10 @@ async function cmdGet(type, id) {
9084
9807
  return;
9085
9808
  }
9086
9809
  async function cmdValidate(path) {
9087
- const essencePath = path || join31(process.cwd(), "decantr.essence.json");
9810
+ const essencePath = path || join32(process.cwd(), "decantr.essence.json");
9088
9811
  let raw;
9089
9812
  try {
9090
- raw = readFileSync22(essencePath, "utf-8");
9813
+ raw = readFileSync23(essencePath, "utf-8");
9091
9814
  } catch {
9092
9815
  console.error(error2(`Could not read ${essencePath}`));
9093
9816
  process.exitCode = 1;
@@ -9154,7 +9877,7 @@ async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet
9154
9877
  return;
9155
9878
  }
9156
9879
  const registryClient = new RegistryClient({
9157
- cacheDir: join31(process.cwd(), ".decantr", "cache")
9880
+ cacheDir: join32(process.cwd(), ".decantr", "cache")
9158
9881
  });
9159
9882
  const result = await registryClient.fetchContentList(
9160
9883
  type,
@@ -9237,10 +9960,10 @@ ${CYAN9}Telemetry enabled.${RESET16} Decantr will send privacy-filtered CLI prod
9237
9960
  }
9238
9961
  function readCliPackageVersion2() {
9239
9962
  const here = dirname6(fileURLToPath3(import.meta.url));
9240
- const candidates = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
9963
+ const candidates = [join32(here, "..", "package.json"), join32(here, "..", "..", "package.json")];
9241
9964
  for (const candidate of candidates) {
9242
9965
  try {
9243
- const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
9966
+ const pkg = JSON.parse(readFileSync23(candidate, "utf-8"));
9244
9967
  if (pkg.version) return pkg.version;
9245
9968
  } catch {
9246
9969
  }
@@ -9251,19 +9974,19 @@ function timestampForFile() {
9251
9974
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9252
9975
  }
9253
9976
  function backupExistingEssence(projectRoot, label) {
9254
- const essencePath = join31(projectRoot, "decantr.essence.json");
9255
- if (!existsSync29(essencePath)) return null;
9256
- const backupPath = join31(
9977
+ const essencePath = join32(projectRoot, "decantr.essence.json");
9978
+ if (!existsSync30(essencePath)) return null;
9979
+ const backupPath = join32(
9257
9980
  projectRoot,
9258
9981
  `decantr.essence.${label}.${timestampForFile()}.backup.json`
9259
9982
  );
9260
- writeFileSync19(backupPath, readFileSync22(essencePath, "utf-8"), "utf-8");
9983
+ writeFileSync20(backupPath, readFileSync23(essencePath, "utf-8"), "utf-8");
9261
9984
  return backupPath;
9262
9985
  }
9263
9986
  function writeBrownfieldProjectJson(input) {
9264
- const decantrDir = join31(input.projectRoot, ".decantr");
9265
- mkdirSync16(join31(decantrDir, "context"), { recursive: true });
9266
- mkdirSync16(join31(decantrDir, "cache"), { recursive: true });
9987
+ const decantrDir = join32(input.projectRoot, ".decantr");
9988
+ mkdirSync17(join32(decantrDir, "context"), { recursive: true });
9989
+ mkdirSync17(join32(decantrDir, "cache"), { recursive: true });
9267
9990
  const now = (/* @__PURE__ */ new Date()).toISOString();
9268
9991
  const projectJson = {
9269
9992
  detected: {
@@ -9304,7 +10027,7 @@ function writeBrownfieldProjectJson(input) {
9304
10027
  }
9305
10028
  }
9306
10029
  };
9307
- writeFileSync19(join31(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
10030
+ writeFileSync20(join32(decantrDir, "project.json"), JSON.stringify(projectJson, null, 2) + "\n");
9308
10031
  }
9309
10032
  async function applyAcceptedBrownfieldProposal(input) {
9310
10033
  const proposal = readBrownfieldProposal(input.projectRoot);
@@ -9320,8 +10043,8 @@ async function applyAcceptedBrownfieldProposal(input) {
9320
10043
  process.exitCode = 1;
9321
10044
  return;
9322
10045
  }
9323
- const essencePath = join31(input.projectRoot, "decantr.essence.json");
9324
- const hasEssence = existsSync29(essencePath);
10046
+ const essencePath = join32(input.projectRoot, "decantr.essence.json");
10047
+ const hasEssence = existsSync30(essencePath);
9325
10048
  let essence;
9326
10049
  let backupPath = null;
9327
10050
  if (input.mode === "accept" && hasEssence) {
@@ -9335,7 +10058,7 @@ async function applyAcceptedBrownfieldProposal(input) {
9335
10058
  return;
9336
10059
  }
9337
10060
  if (input.mode === "merge" && hasEssence) {
9338
- const existing = JSON.parse(readFileSync22(essencePath, "utf-8"));
10061
+ const existing = JSON.parse(readFileSync23(essencePath, "utf-8"));
9339
10062
  if (!isV49(existing)) {
9340
10063
  console.log(
9341
10064
  error2(
@@ -9372,9 +10095,9 @@ async function applyAcceptedBrownfieldProposal(input) {
9372
10095
  assistantBridge: input.assistantBridge,
9373
10096
  mode: input.mode
9374
10097
  });
9375
- writeFileSync19(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
10098
+ writeFileSync20(essencePath, JSON.stringify(essence, null, 2) + "\n", "utf-8");
9376
10099
  const registryClient = new RegistryClient({
9377
- cacheDir: join31(input.projectRoot, ".decantr", "cache"),
10100
+ cacheDir: join32(input.projectRoot, ".decantr", "cache"),
9378
10101
  offline: true,
9379
10102
  projectRoot: input.projectRoot
9380
10103
  });
@@ -9553,7 +10276,7 @@ async function cmdInit(args) {
9553
10276
  }
9554
10277
  }
9555
10278
  const registryClient = new RegistryClient({
9556
- cacheDir: join31(projectRoot, ".decantr", "cache"),
10279
+ cacheDir: join32(projectRoot, ".decantr", "cache"),
9557
10280
  apiUrl: args.registry,
9558
10281
  offline: args.offline,
9559
10282
  projectRoot
@@ -9885,7 +10608,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
9885
10608
  if (appliedRuleFiles.length > 0) {
9886
10609
  console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
9887
10610
  }
9888
- if (!existsSync29(join31(projectRoot, "package.json"))) {
10611
+ if (!existsSync30(join32(projectRoot, "package.json"))) {
9889
10612
  console.log("");
9890
10613
  console.log(
9891
10614
  dim3(` Note: ${cyan3("decantr init")} created Decantr contract/context files only.`)
@@ -9896,7 +10619,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
9896
10619
  )
9897
10620
  );
9898
10621
  }
9899
- const hasCompiledPacks = existsSync29(join31(projectRoot, ".decantr", "context", "scaffold-pack.md"));
10622
+ const hasCompiledPacks = existsSync30(join32(projectRoot, ".decantr", "context", "scaffold-pack.md"));
9900
10623
  console.log("");
9901
10624
  console.log(" Next steps:");
9902
10625
  if (hasCompiledPacks) {
@@ -9936,7 +10659,7 @@ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
9936
10659
  console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
9937
10660
  console.log(` ${cyan3("decantr check")} Detect drift issues`);
9938
10661
  console.log(` ${cyan3("decantr migrate --to v4")} Migrate older essence files to v4`);
9939
- const essenceContent = readFileSync22(result.essencePath, "utf-8");
10662
+ const essenceContent = readFileSync23(result.essencePath, "utf-8");
9940
10663
  const essence = JSON.parse(essenceContent);
9941
10664
  const validation = validateEssence2(essence);
9942
10665
  if (!validation.valid) {
@@ -9991,16 +10714,16 @@ Validation warnings: ${validation.errors.join(", ")}`));
9991
10714
  }
9992
10715
  }
9993
10716
  async function cmdStatus(projectRoot = process.cwd()) {
9994
- const essencePath = join31(projectRoot, "decantr.essence.json");
9995
- const projectJsonPath = join31(projectRoot, ".decantr", "project.json");
10717
+ const essencePath = join32(projectRoot, "decantr.essence.json");
10718
+ const projectJsonPath = join32(projectRoot, ".decantr", "project.json");
9996
10719
  console.log(heading2("Decantr Project Status"));
9997
- if (!existsSync29(essencePath)) {
10720
+ if (!existsSync30(essencePath)) {
9998
10721
  console.log(`${RED12}No decantr.essence.json found.${RESET16}`);
9999
10722
  console.log(dim3('Run "decantr init" to create one.'));
10000
10723
  return;
10001
10724
  }
10002
10725
  try {
10003
- const essence = JSON.parse(readFileSync22(essencePath, "utf-8"));
10726
+ const essence = JSON.parse(readFileSync23(essencePath, "utf-8"));
10004
10727
  const validation = validateEssence2(essence);
10005
10728
  const essenceVersion = isV49(essence) ? "v4" : "legacy";
10006
10729
  console.log(`${BOLD9}Essence:${RESET16}`);
@@ -10048,9 +10771,9 @@ async function cmdStatus(projectRoot = process.cwd()) {
10048
10771
  }
10049
10772
  console.log("");
10050
10773
  console.log(`${BOLD9}Sync Status:${RESET16}`);
10051
- if (existsSync29(projectJsonPath)) {
10774
+ if (existsSync30(projectJsonPath)) {
10052
10775
  try {
10053
- const projectJson = JSON.parse(readFileSync22(projectJsonPath, "utf-8"));
10776
+ const projectJson = JSON.parse(readFileSync23(projectJsonPath, "utf-8"));
10054
10777
  const syncStatus = projectJson.sync?.status || "unknown";
10055
10778
  const lastSync = projectJson.sync?.lastSync || "never";
10056
10779
  const source = projectJson.sync?.registrySource || "unknown";
@@ -10068,7 +10791,7 @@ async function cmdStatus(projectRoot = process.cwd()) {
10068
10791
  }
10069
10792
  async function cmdSync() {
10070
10793
  const projectRoot = process.cwd();
10071
- const cacheDir = join31(projectRoot, ".decantr", "cache");
10794
+ const cacheDir = join32(projectRoot, ".decantr", "cache");
10072
10795
  console.log(heading2("Syncing registry content..."));
10073
10796
  const result = await syncRegistry(cacheDir);
10074
10797
  if (result.synced.length > 0) {
@@ -10262,14 +10985,14 @@ ${BOLD9}Examples:${RESET16}
10262
10985
  process.exitCode = 1;
10263
10986
  return;
10264
10987
  }
10265
- const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
10266
- if (!existsSync29(themePath)) {
10988
+ const themePath = join32(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
10989
+ if (!existsSync30(themePath)) {
10267
10990
  console.error(error2(`Theme "${name}" not found at ${themePath}`));
10268
10991
  process.exitCode = 1;
10269
10992
  return;
10270
10993
  }
10271
10994
  try {
10272
- const theme = JSON.parse(readFileSync22(themePath, "utf-8"));
10995
+ const theme = JSON.parse(readFileSync23(themePath, "utf-8"));
10273
10996
  const result = validateCustomTheme(theme);
10274
10997
  if (result.valid) {
10275
10998
  console.log(success3(`Custom theme "${name}" is valid`));
@@ -10401,7 +11124,7 @@ function withProject(command, projectArg) {
10401
11124
  return projectArg ? `${command} --project ${projectArg}` : command;
10402
11125
  }
10403
11126
  function displayProjectPath(workspaceInfo, projectPath) {
10404
- const absolutePath = join31(workspaceInfo.appRoot, projectPath);
11127
+ const absolutePath = join32(workspaceInfo.appRoot, projectPath);
10405
11128
  const relativePath = relative7(workspaceInfo.cwd, absolutePath).replace(/\\/g, "/");
10406
11129
  if (relativePath && !relativePath.startsWith("..") && !isAbsolute3(relativePath)) {
10407
11130
  return relativePath;
@@ -10460,6 +11183,7 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
10460
11183
  console.log("");
10461
11184
  console.log("Start by attaching one app:");
10462
11185
  console.log(` ${cyan3(`decantr adopt --project ${candidate} --yes`)}`);
11186
+ console.log(` ${cyan3(`decantr codify --from-audit --style-bridge --project ${candidate}`)}`);
10463
11187
  console.log("");
10464
11188
  console.log("Optional visual evidence after the app is running:");
10465
11189
  console.log(
@@ -10469,7 +11193,7 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
10469
11193
  function printMonorepoSetupGuidance(workspaceInfo) {
10470
11194
  const candidate = firstWorkspaceCandidate(workspaceInfo);
10471
11195
  const attachedProjects = workspaceInfo.appCandidates.filter(
10472
- (appCandidate) => existsSync29(join31(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
11196
+ (appCandidate) => existsSync30(join32(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
10473
11197
  );
10474
11198
  const firstAttached = attachedProjects[0];
10475
11199
  console.log(heading2("Decantr Setup"));
@@ -10526,7 +11250,7 @@ function printMonorepoSetupGuidance(workspaceInfo) {
10526
11250
  ` ${cyan3(`decantr adopt --project ${candidate} --yes`)} Attach Decantr to one app`
10527
11251
  );
10528
11252
  console.log(
10529
- ` ${cyan3(`decantr codify --from-audit --project ${candidate}`)} Propose project-owned UI law`
11253
+ ` ${cyan3(`decantr codify --from-audit --style-bridge --project ${candidate}`)} Propose project-owned UI law and style bridge`
10530
11254
  );
10531
11255
  console.log("");
10532
11256
  console.log(`${BOLD9}Optional visual evidence:${RESET16}`);
@@ -10537,14 +11261,19 @@ function printMonorepoSetupGuidance(workspaceInfo) {
10537
11261
  function resolveWorkflowProject(flags, commandName = "command", options = {}) {
10538
11262
  const projectArg = flagString(flags, "project");
10539
11263
  const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
10540
- if (projectArg && options.requireExisting !== false && !existsSync29(workspaceInfo.appRoot)) {
11264
+ if (projectArg && options.requireExisting !== false && !existsSync30(workspaceInfo.appRoot)) {
10541
11265
  printProjectNotFound(projectArg, commandName);
10542
11266
  process.exitCode = 1;
10543
11267
  return null;
10544
11268
  }
10545
11269
  if (projectArg && options.requireAppCandidate && workspaceInfo.appCandidates.length > 0) {
10546
11270
  const normalizedProject = normalizedProjectPath(projectArg);
10547
- const knownCandidate = normalizedProject ? workspaceInfo.appCandidates.includes(normalizedProject) : false;
11271
+ const normalizedWorkspaceProject = normalizedProjectPath(
11272
+ relative7(workspaceInfo.workspaceRoot, workspaceInfo.appRoot)
11273
+ );
11274
+ const knownCandidate = normalizedProject ? workspaceInfo.appCandidates.includes(normalizedProject) || Boolean(
11275
+ normalizedWorkspaceProject && workspaceInfo.appCandidates.includes(normalizedWorkspaceProject)
11276
+ ) : false;
10548
11277
  const forcePackage = flagBoolean(flags, "force-package") || flagBoolean(flags, "allow-package") || flagBoolean(flags, "force");
10549
11278
  if (!knownCandidate && !forcePackage && !options.allowPackageProject) {
10550
11279
  console.error(
@@ -10577,6 +11306,101 @@ function printWorkflowPlan(title, steps) {
10577
11306
  }
10578
11307
  console.log("");
10579
11308
  }
11309
+ function scanSeverityColor(finding) {
11310
+ if (finding.severity === "success") return success3("ok");
11311
+ if (finding.severity === "error") return error2("error");
11312
+ if (finding.severity === "warn") return `${YELLOW12}warn${RESET16}`;
11313
+ return cyan3("info");
11314
+ }
11315
+ function formatScanApplicability(status) {
11316
+ if (status === "strong_fit") return success3("strong fit");
11317
+ if (status === "partial_fit") return `${YELLOW12}partial fit${RESET16}`;
11318
+ if (status === "not_applicable") return dim3("not applicable");
11319
+ return dim3("unknown");
11320
+ }
11321
+ function printScanReport(report) {
11322
+ console.log(heading2("Decantr Scan"));
11323
+ console.log(dim3("Read-only Brownfield reconnaissance. No files were written."));
11324
+ console.log("");
11325
+ console.log(`${BOLD9}Verdict${RESET16}`);
11326
+ console.log(` ${formatScanApplicability(report.applicability.status)} ${report.applicability.label}`);
11327
+ console.log(
11328
+ ` Confidence: ${cyan3(`${report.confidence.score}/100`)} (${report.confidence.level})`
11329
+ );
11330
+ for (const reason of report.applicability.reasons.slice(0, 3)) {
11331
+ console.log(` ${dim3("-")} ${reason}`);
11332
+ }
11333
+ console.log("");
11334
+ console.log(`${BOLD9}Project${RESET16}`);
11335
+ console.log(` Framework: ${cyan3(report.project.framework)}${report.project.frameworkVersion ? ` ${report.project.frameworkVersion}` : ""}`);
11336
+ console.log(` Package manager:${" "} ${report.project.packageManager}`);
11337
+ console.log(` Language: ${report.project.primaryLanguage}`);
11338
+ console.log(` TypeScript: ${report.project.hasTypeScript ? "yes" : "no"}`);
11339
+ console.log(` Decantr: ${report.project.hasDecantr ? "present" : "not attached"}`);
11340
+ console.log("");
11341
+ console.log(`${BOLD9}Routes And Styling${RESET16}`);
11342
+ console.log(` Routes: ${report.routes.count} (${report.routes.strategy})`);
11343
+ for (const route of report.routes.items.slice(0, 8)) {
11344
+ console.log(` ${cyan3(route.path.padEnd(18))} ${dim3(route.file)}`);
11345
+ }
11346
+ if (report.routes.items.length > 8) {
11347
+ console.log(` ${dim3(`...${report.routes.items.length - 8} more route(s)`)}`);
11348
+ }
11349
+ console.log(` Components: ${report.components.componentCount}`);
11350
+ console.log(
11351
+ ` Styling: ${report.styling.approach}${report.styling.configFile ? ` (${report.styling.configFile})` : ""}`
11352
+ );
11353
+ console.log(` CSS variables: ${report.styling.cssVariableCount}`);
11354
+ console.log(` Dark mode: ${report.styling.darkMode ? "yes" : "no"}`);
11355
+ console.log("");
11356
+ if (report.staticHosting.githubPagesLikely || report.pagesProbe) {
11357
+ console.log(`${BOLD9}Published Surface${RESET16}`);
11358
+ console.log(` GitHub Pages: ${report.staticHosting.githubPagesLikely ? "likely" : "not detected"}`);
11359
+ if (report.source.publishedSiteUrl) {
11360
+ console.log(` Site URL: ${report.source.publishedSiteUrl}`);
11361
+ }
11362
+ if (report.pagesProbe?.checked) {
11363
+ console.log(
11364
+ ` HTTP probe: ${report.pagesProbe.reachable ? success3("reachable") : `${YELLOW12}unreachable${RESET16}`} ${report.pagesProbe.status ?? ""}`
11365
+ );
11366
+ if (report.pagesProbe.title) console.log(` Title: ${report.pagesProbe.title}`);
11367
+ }
11368
+ for (const item of report.staticHosting.evidence.slice(0, 4)) {
11369
+ console.log(` ${dim3("-")} ${item}`);
11370
+ }
11371
+ console.log("");
11372
+ }
11373
+ console.log(`${BOLD9}Findings${RESET16}`);
11374
+ for (const finding of report.findings.slice(0, 8)) {
11375
+ console.log(` [${scanSeverityColor(finding)}] ${finding.title}`);
11376
+ console.log(` ${finding.message}`);
11377
+ if (finding.recommendation) console.log(` ${dim3(finding.recommendation)}`);
11378
+ }
11379
+ console.log("");
11380
+ console.log(`${BOLD9}Next Commands${RESET16}`);
11381
+ for (const command of report.recommendedCommands) {
11382
+ console.log(` ${cyan3(command)}`);
11383
+ }
11384
+ console.log("");
11385
+ console.log(dim3(report.privacy.notes[0] ?? "Scan completed without writing files."));
11386
+ }
11387
+ async function cmdScanWorkflow(args) {
11388
+ const { flags } = parseLooseArgs(args);
11389
+ if (!ensureAllowedFlags(flags, ["project", "json"], "scan")) return;
11390
+ const workspaceInfo = resolveWorkflowProject(flags, "scan");
11391
+ if (!workspaceInfo) return;
11392
+ const jsonOutput = flagBoolean(flags, "json");
11393
+ const projectArg = flagString(flags, "project");
11394
+ const inputValue = projectArg ?? ".";
11395
+ const report = await scanProjectReadOnly(workspaceInfo.appRoot, {
11396
+ input: { kind: "local", value: inputValue }
11397
+ });
11398
+ if (jsonOutput) {
11399
+ console.log(JSON.stringify(report, null, 2));
11400
+ return;
11401
+ }
11402
+ printScanReport(report);
11403
+ }
10580
11404
  async function cmdSetupWorkflow(args) {
10581
11405
  const { flags } = parseLooseArgs(args);
10582
11406
  const projectArg = flagString(flags, "project");
@@ -10597,21 +11421,27 @@ async function cmdSetupWorkflow(args) {
10597
11421
  console.log(` Detected: ${formatDetection(detected)}`);
10598
11422
  console.log("");
10599
11423
  if (detected.existingEssence) {
10600
- const hasLocalPatterns = existsSync29(localPatternsPath(workspaceInfo.appRoot));
10601
- const hasLocalRules = existsSync29(localRulesPath(workspaceInfo.appRoot));
11424
+ const hasLocalPatterns = existsSync30(localPatternsPath(workspaceInfo.appRoot));
11425
+ const hasLocalRules = existsSync30(localRulesPath(workspaceInfo.appRoot));
11426
+ const hasStyleBridge = existsSync30(styleBridgePath(workspaceInfo.appRoot));
10602
11427
  const verifyCommand = hasLocalPatterns || hasLocalRules ? "decantr verify --brownfield --local-patterns" : "decantr verify --brownfield";
10603
11428
  console.log(`${BOLD9}Recommended path:${RESET16} maintain an attached Decantr project`);
11429
+ console.log(
11430
+ ` ${cyan3(withProject("decantr doctor", projectArg))} Explain current state and next command`
11431
+ );
11432
+ if (!hasLocalPatterns || !hasLocalRules || !hasStyleBridge) {
11433
+ const codifyCommand = hasLocalPatterns && hasLocalRules ? "decantr codify --style-bridge" : "decantr codify --from-audit --style-bridge";
11434
+ console.log(
11435
+ ` ${cyan3(withProject(codifyCommand, projectArg))} Propose missing local law/style bridge`
11436
+ );
11437
+ }
10604
11438
  console.log(
10605
11439
  ` ${cyan3(withProject('decantr task <route> "<change>"', projectArg))} Prepare LLM context before edits`
10606
11440
  );
10607
11441
  console.log(
10608
11442
  ` ${cyan3(withProject(verifyCommand, projectArg))} Run local health and drift checks`
10609
11443
  );
10610
- if (!hasLocalPatterns || !hasLocalRules) {
10611
- console.log(
10612
- ` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose project-owned local law`
10613
- );
10614
- }
11444
+ console.log(` ${cyan3(withProject("decantr ci init", projectArg))} Wire the app into CI`);
10615
11445
  return;
10616
11446
  }
10617
11447
  if (hasFootprint) {
@@ -10620,7 +11450,7 @@ async function cmdSetupWorkflow(args) {
10620
11450
  ` ${cyan3(withProject("decantr adopt --yes", projectArg))} Analyze, attach, and verify`
10621
11451
  );
10622
11452
  console.log(
10623
- ` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose local UI law`
11453
+ ` ${cyan3(withProject("decantr codify --from-audit --style-bridge", projectArg))} Propose local UI law and style bridge`
10624
11454
  );
10625
11455
  console.log("");
10626
11456
  console.log(`${BOLD9}Optional visual evidence after the app is running:${RESET16}`);
@@ -10679,7 +11509,7 @@ async function cmdAdoptWorkflow(args) {
10679
11509
  const hydratePacks = flagBoolean(flags, "packs", true) && !flagBoolean(flags, "skip-packs") && !flagBoolean(flags, "offline") && process.env.DECANTR_OFFLINE !== "true";
10680
11510
  const initCi = flagBoolean(flags, "ci") || flagBoolean(flags, "init-ci");
10681
11511
  const assistantBridge = flagString(flags, "assistant-bridge");
10682
- const hasEssence = existsSync29(join31(projectRoot, "decantr.essence.json"));
11512
+ const hasEssence = existsSync30(join32(projectRoot, "decantr.essence.json"));
10683
11513
  const proposalFlag = flagBoolean(flags, "replace-essence") ? "--replace-essence" : flagBoolean(flags, "merge-proposal") || hasEssence ? "--merge-proposal" : "--accept-proposal";
10684
11514
  const steps = [
10685
11515
  "analyze current app and write .decantr/brownfield intelligence",
@@ -10727,7 +11557,7 @@ async function cmdAdoptWorkflow(args) {
10727
11557
  if (hydratePacks) {
10728
11558
  try {
10729
11559
  const { bundle, contextDir } = await compileHostedExecutionPackBundle(
10730
- join31(projectRoot, "decantr.essence.json")
11560
+ join32(projectRoot, "decantr.essence.json")
10731
11561
  );
10732
11562
  const written = writeHostedExecutionPackContextArtifacts(
10733
11563
  contextDir,
@@ -10750,7 +11580,7 @@ async function cmdAdoptWorkflow(args) {
10750
11580
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
10751
11581
  }
10752
11582
  if (runVerify) {
10753
- const { cmdHealth } = await import("./health-ADHNLMX3.js");
11583
+ const { cmdHealth } = await import("./health-B4W7UJBZ.js");
10754
11584
  await cmdHealth(projectRoot, {
10755
11585
  browser: runBrowser,
10756
11586
  browserBaseUrl: baseUrl,
@@ -10768,10 +11598,10 @@ async function cmdAdoptWorkflow(args) {
10768
11598
  console.log("");
10769
11599
  console.log(`${BOLD9}Brownfield operating loop:${RESET16}`);
10770
11600
  console.log(
10771
- ` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Discover and propose project-owned UI law`
11601
+ ` ${cyan3(withProject("decantr codify --from-audit --style-bridge", projectArg))} Propose project-owned UI law and style bridge`
10772
11602
  );
10773
11603
  console.log(
10774
- ` ${cyan3(withProject("decantr codify --accept", projectArg))} Accept reviewed local patterns and rules`
11604
+ ` ${cyan3(withProject("decantr codify --accept", projectArg))} Accept reviewed local patterns, rules, and bridge`
10775
11605
  );
10776
11606
  console.log(
10777
11607
  ` ${cyan3(withProject('decantr task <route> "<change>"', projectArg))} Give your LLM route-specific context before edits`
@@ -10821,7 +11651,7 @@ async function cmdVerifyWorkflow(args) {
10821
11651
  return;
10822
11652
  }
10823
11653
  if (workspaceMode) {
10824
- const { cmdWorkspace } = await import("./workspace-YYCRXJNB.js");
11654
+ const { cmdWorkspace } = await import("./workspace-7RU77ZZW.js");
10825
11655
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
10826
11656
  return;
10827
11657
  }
@@ -10854,7 +11684,7 @@ async function cmdVerifyWorkflow(args) {
10854
11684
  }
10855
11685
  let guardExitCode;
10856
11686
  if (brownfield) {
10857
- const { cmdHeal, collectCheckIssues } = await import("./heal-2UCSPRTK.js");
11687
+ const { cmdHeal, collectCheckIssues } = await import("./heal-IRIDB7IZ.js");
10858
11688
  if (quietOutput) {
10859
11689
  const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
10860
11690
  guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
@@ -10864,7 +11694,7 @@ async function cmdVerifyWorkflow(args) {
10864
11694
  process.exitCode = void 0;
10865
11695
  }
10866
11696
  }
10867
- const { cmdHealth, parseHealthArgs } = await import("./health-ADHNLMX3.js");
11697
+ const { cmdHealth, parseHealthArgs } = await import("./health-B4W7UJBZ.js");
10868
11698
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10869
11699
  if (localPatterns) {
10870
11700
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10886,6 +11716,9 @@ async function cmdVerifyWorkflow(args) {
10886
11716
  console.log(`${GREEN16}Local pattern pack found:${RESET16} ${validation.patternsPath}`);
10887
11717
  if (validation.ruleManifestPresent) {
10888
11718
  console.log(`${GREEN16}Local rule manifest found:${RESET16} ${validation.rulesPath}`);
11719
+ console.log(
11720
+ `${DIM16}Enforcement: accepted .decantr/rules.json is the Decantr-scanned layer; --fail-on controls whether findings block.${RESET16}`
11721
+ );
10889
11722
  } else {
10890
11723
  console.log(
10891
11724
  `${YELLOW12}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
@@ -10914,14 +11747,25 @@ async function cmdVerifyWorkflow(args) {
10914
11747
  }
10915
11748
  }
10916
11749
  }
11750
+ const styleBridge = createStyleBridgeTaskSummary(workspaceInfo.appRoot);
11751
+ if (!quietOutput && styleBridge.path) {
11752
+ console.log("");
11753
+ console.log(`${GREEN16}Style bridge found:${RESET16} ${styleBridge.path}`);
11754
+ console.log(
11755
+ `${DIM16}${styleBridge.mappingCount} mapping(s), ${styleBridge.stylingApproach ?? "unknown"} styling${styleBridge.themeModes.length > 0 ? `, themes: ${styleBridge.themeModes.join(", ")}` : ""}${RESET16}`
11756
+ );
11757
+ console.log(
11758
+ `${DIM16}Enforcement: advisory style-intent mapping; pair with accepted local rules, lint, tests, or visual regression when it should block.${RESET16}`
11759
+ );
11760
+ }
10917
11761
  if (guardExitCode && guardExitCode !== 0 && (!process.exitCode || process.exitCode === 0)) {
10918
11762
  process.exitCode = guardExitCode;
10919
11763
  }
10920
11764
  }
10921
11765
  function readJsonIfPresent(path) {
10922
- if (!existsSync29(path)) return null;
11766
+ if (!existsSync30(path)) return null;
10923
11767
  try {
10924
- return JSON.parse(readFileSync22(path, "utf-8"));
11768
+ return JSON.parse(readFileSync23(path, "utf-8"));
10925
11769
  } catch {
10926
11770
  return null;
10927
11771
  }
@@ -10933,6 +11777,7 @@ function mentionsWord(text, term) {
10933
11777
  function createTaskAuthoritySummary(input) {
10934
11778
  const detected = detectProject(input.projectRoot);
10935
11779
  const hasLocalLaw = input.hasLocalPatterns || input.hasLocalRules;
11780
+ const hasStyleBridge = input.hasStyleBridge || input.adoptionMode === "style-bridge";
10936
11781
  let lane = "Brownfield contract-only";
10937
11782
  let sourceAuthority = "Existing app is authoritative; Decantr supplies contract context.";
10938
11783
  let styleAuthority = "Use the existing styling system.";
@@ -10945,11 +11790,11 @@ function createTaskAuthoritySummary(input) {
10945
11790
  sourceAuthority = "Existing app remains authoritative except where Decantr CSS is explicitly adopted.";
10946
11791
  styleAuthority = "Decantr CSS runtime is active where adopted.";
10947
11792
  activeAuthorities.push("Decantr CSS runtime");
10948
- } else if (input.workflowMode === "brownfield-attach" && input.adoptionMode === "style-bridge") {
11793
+ } else if (input.workflowMode === "brownfield-attach" && hasStyleBridge) {
10949
11794
  lane = "Hybrid style bridge";
10950
11795
  sourceAuthority = "Existing app remains authoritative; Decantr intent maps through the style bridge.";
10951
11796
  styleAuthority = "Use bridge tokens/classes as a mapping layer onto the app styling system.";
10952
- activeAuthorities.push("style bridge");
11797
+ activeAuthorities.push("accepted style bridge");
10953
11798
  } else if (input.workflowMode === "brownfield-attach" && hasLocalLaw) {
10954
11799
  lane = "Hybrid local law";
10955
11800
  sourceAuthority = "Existing app plus accepted project-owned UI law are authoritative.";
@@ -11018,7 +11863,7 @@ async function cmdTaskWorkflow(args) {
11018
11863
  }
11019
11864
  const route = routeInput.startsWith("/") ? routeInput : `/${routeInput}`;
11020
11865
  const taskSummary = positional.slice(1).join(" ").trim();
11021
- const essencePath = join31(workspaceInfo.appRoot, "decantr.essence.json");
11866
+ const essencePath = join32(workspaceInfo.appRoot, "decantr.essence.json");
11022
11867
  const essence = readJsonIfPresent(essencePath);
11023
11868
  if (!essence) {
11024
11869
  console.error(
@@ -11042,16 +11887,22 @@ async function cmdTaskWorkflow(args) {
11042
11887
  }
11043
11888
  const section = essence.blueprint.sections.find((entry) => entry.id === target.section);
11044
11889
  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"));
11890
+ const contextDir = join32(workspaceInfo.appRoot, ".decantr", "context");
11891
+ const manifest = readJsonIfPresent(join32(contextDir, "pack-manifest.json"));
11892
+ const projectJson = readJsonIfPresent(join32(workspaceInfo.appRoot, ".decantr", "project.json"));
11048
11893
  const pagePack = manifest?.pages?.find((entry) => entry.id === target.page);
11049
11894
  const sectionPack = manifest?.sections?.find((entry) => entry.id === target.section);
11050
- const visualManifest = readJsonIfPresent(join31(workspaceInfo.appRoot, ".decantr", "evidence", "visual-manifest.json"));
11895
+ const visualManifest = readJsonIfPresent(join32(workspaceInfo.appRoot, ".decantr", "evidence", "visual-manifest.json"));
11051
11896
  const screenshot = visualManifest?.routes?.find((entry) => entry.route === route)?.screenshot;
11052
11897
  const localPatternPackPath = localPatternsPath(workspaceInfo.appRoot);
11053
11898
  const localRuleManifestPath = localRulesPath(workspaceInfo.appRoot);
11899
+ const acceptedStyleBridgePath = styleBridgePath(workspaceInfo.appRoot);
11054
11900
  const localLaw = createLocalLawTaskSummary(workspaceInfo.appRoot);
11901
+ const styleBridge = createStyleBridgeTaskSummary(workspaceInfo.appRoot);
11902
+ const displayedStyleBridge = {
11903
+ ...styleBridge,
11904
+ path: styleBridge.path ? displayProjectPath(workspaceInfo, styleBridge.path) : null
11905
+ };
11055
11906
  const displayedLocalLaw = {
11056
11907
  ...localLaw,
11057
11908
  patternsPath: localLaw.patternsPath ? displayProjectPath(workspaceInfo, localLaw.patternsPath) : null,
@@ -11064,10 +11915,11 @@ async function cmdTaskWorkflow(args) {
11064
11915
  projectRoot: workspaceInfo.appRoot,
11065
11916
  workflowMode: projectJson?.initialized?.workflowMode ?? null,
11066
11917
  adoptionMode: projectJson?.initialized?.adoptionMode ?? null,
11067
- hasLocalPatterns: existsSync29(localPatternPackPath),
11068
- hasLocalRules: existsSync29(localRuleManifestPath),
11918
+ hasLocalPatterns: existsSync30(localPatternPackPath),
11919
+ hasLocalRules: existsSync30(localRuleManifestPath),
11069
11920
  hasPackManifest: Boolean(manifest),
11070
- taskSummary
11921
+ taskSummary,
11922
+ hasStyleBridge: existsSync30(acceptedStyleBridgePath)
11071
11923
  });
11072
11924
  const context = {
11073
11925
  route,
@@ -11077,17 +11929,19 @@ async function cmdTaskWorkflow(args) {
11077
11929
  shell: page?.shell ?? section?.shell ?? null,
11078
11930
  patterns: page?.layout?.map(extractPatternName) ?? [],
11079
11931
  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,
11932
+ pagePack ? displayProjectPath(workspaceInfo, join32(".decantr/context", pagePack.markdown)) : null,
11933
+ sectionPack ? displayProjectPath(workspaceInfo, join32(".decantr/context", sectionPack.markdown)) : null,
11934
+ manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join32(".decantr/context", manifest.scaffold.markdown)) : null,
11083
11935
  displayProjectPath(workspaceInfo, ".decantr/context/scaffold.md"),
11084
11936
  displayProjectPath(workspaceInfo, "DECANTR.md"),
11085
- existsSync29(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
11086
- existsSync29(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null
11937
+ existsSync30(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
11938
+ existsSync30(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null,
11939
+ existsSync30(acceptedStyleBridgePath) ? displayProjectPath(workspaceInfo, ".decantr/style-bridge.json") : null
11087
11940
  ].filter(Boolean),
11088
11941
  screenshot: screenshot?.startsWith(".decantr/") ? displayProjectPath(workspaceInfo, screenshot) : screenshot ?? null,
11089
11942
  authority,
11090
11943
  localLaw: displayedLocalLaw,
11944
+ styleBridge: displayedStyleBridge,
11091
11945
  changedFiles: currentChangedFiles,
11092
11946
  changedRoutes,
11093
11947
  verifyCommand: withProject("decantr verify --brownfield --local-patterns", projectArg)
@@ -11132,10 +11986,17 @@ async function cmdTaskWorkflow(args) {
11132
11986
  }
11133
11987
  if (context.localLaw.rulesPath) {
11134
11988
  console.log(` Rules: ${cyan3(context.localLaw.rulesPath)} (${context.localLaw.ruleCount})`);
11989
+ console.log(" Enforcement: accepted local rules are the Decantr-scanned layer.");
11135
11990
  }
11136
11991
  for (const pattern of context.localLaw.patterns.slice(0, 4)) {
11137
11992
  const pathHint = pattern.componentPaths.length > 0 ? ` \u2014 ${pattern.componentPaths.slice(0, 2).join(", ")}` : "";
11138
- console.log(` ${pattern.id}: ${pattern.role ?? "local pattern"}${pathHint}`);
11993
+ const authorityHint = [
11994
+ pattern.role ?? "local pattern",
11995
+ pattern.confidenceTier ? `confidence ${pattern.confidenceTier}` : null,
11996
+ pattern.enforcementLevel ? `${pattern.enforcementLevel}` : null,
11997
+ pattern.hostedPatternRefs.length > 0 ? `maps ${pattern.hostedPatternRefs.slice(0, 2).join(", ")}` : null
11998
+ ].filter(Boolean).join(" | ");
11999
+ console.log(` ${pattern.id}: ${authorityHint}${pathHint}`);
11139
12000
  }
11140
12001
  } else {
11141
12002
  console.log("");
@@ -11144,6 +12005,23 @@ async function cmdTaskWorkflow(args) {
11144
12005
  ` ${YELLOW12}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
11145
12006
  );
11146
12007
  }
12008
+ if (context.styleBridge.path) {
12009
+ console.log("");
12010
+ console.log(`${BOLD9}Project-owned style bridge:${RESET16}`);
12011
+ console.log(
12012
+ ` Bridge: ${cyan3(context.styleBridge.path)} (${context.styleBridge.mappingCount} mappings, ${context.styleBridge.stylingApproach ?? "unknown"} styling)`
12013
+ );
12014
+ console.log(
12015
+ " Enforcement: advisory mapping layer; accepted local rules or project lint/tests do the blocking."
12016
+ );
12017
+ if (context.styleBridge.themeModes.length > 0) {
12018
+ console.log(` Theme modes: ${context.styleBridge.themeModes.join(", ")}`);
12019
+ }
12020
+ for (const mapping of context.styleBridge.mappings.slice(0, 4)) {
12021
+ const hints = [...mapping.tokenHints, ...mapping.classHints].slice(0, 4).join(", ");
12022
+ console.log(` ${mapping.id}: ${mapping.label}${hints ? ` \u2014 ${hints}` : ""}`);
12023
+ }
12024
+ }
11147
12025
  if (context.changedFiles.length > 0) {
11148
12026
  console.log("");
11149
12027
  console.log(`${BOLD9}Changed-file context:${RESET16}`);
@@ -11169,7 +12047,16 @@ async function cmdCodifyWorkflow(args) {
11169
12047
  const projectArg = flagString(flags, "project");
11170
12048
  if (!ensureAllowedFlags(
11171
12049
  flags,
11172
- ["project", "from-audit", "discover-local-patterns", "codify-local-patterns", "accept"],
12050
+ [
12051
+ "project",
12052
+ "from-audit",
12053
+ "discover-local-patterns",
12054
+ "codify-local-patterns",
12055
+ "style-bridge",
12056
+ "map-pattern",
12057
+ "hosted-pattern",
12058
+ "accept"
12059
+ ],
11173
12060
  "codify"
11174
12061
  )) {
11175
12062
  return;
@@ -11177,25 +12064,29 @@ async function cmdCodifyWorkflow(args) {
11177
12064
  const workspaceInfo = resolveWorkflowProject(flags, "codify");
11178
12065
  if (!workspaceInfo) return;
11179
12066
  if (flagBoolean(flags, "accept")) {
11180
- if (!existsSync29(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync29(localRulesProposalPath(workspaceInfo.appRoot))) {
12067
+ if (!existsSync30(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync30(localRulesProposalPath(workspaceInfo.appRoot)) && !existsSync30(styleBridgeProposalPath(workspaceInfo.appRoot))) {
11181
12068
  console.error(
11182
12069
  error2(
11183
- "No local law proposal found. Run `decantr codify --from-audit` or `decantr codify` first."
12070
+ "No codify proposal found. Run `decantr codify --from-audit`, `decantr codify --style-bridge`, or `decantr codify` first."
11184
12071
  )
11185
12072
  );
11186
12073
  process.exitCode = 1;
11187
12074
  return;
11188
12075
  }
11189
- const result2 = acceptBrownfieldLocalLaw(workspaceInfo.appRoot);
11190
- if (result2.patternAcceptedPath) {
11191
- console.log(success3(`Accepted local pattern pack: ${result2.patternAcceptedPath}`));
12076
+ const result = acceptBrownfieldLocalLaw(workspaceInfo.appRoot);
12077
+ const bridgeAcceptedPath = acceptStyleBridge(workspaceInfo.appRoot);
12078
+ if (result.patternAcceptedPath) {
12079
+ console.log(success3(`Accepted local pattern pack: ${result.patternAcceptedPath}`));
11192
12080
  }
11193
- if (result2.rulesAcceptedPath) {
11194
- console.log(success3(`Accepted local rule manifest: ${result2.rulesAcceptedPath}`));
12081
+ if (result.rulesAcceptedPath) {
12082
+ console.log(success3(`Accepted local rule manifest: ${result.rulesAcceptedPath}`));
12083
+ }
12084
+ if (bridgeAcceptedPath) {
12085
+ console.log(success3(`Accepted style bridge: ${bridgeAcceptedPath}`));
11195
12086
  }
11196
12087
  console.log(
11197
12088
  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."
12089
+ 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
12090
  )
11200
12091
  );
11201
12092
  console.log(
@@ -11207,19 +12098,84 @@ async function cmdCodifyWorkflow(args) {
11207
12098
  }
11208
12099
  const detected = detectProject(workspaceInfo.appRoot);
11209
12100
  const essence = readJsonIfPresent(
11210
- join31(workspaceInfo.appRoot, "decantr.essence.json")
12101
+ join32(workspaceInfo.appRoot, "decantr.essence.json")
11211
12102
  );
11212
12103
  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) {
12104
+ const wantsStyleBridge = flagBoolean(flags, "style-bridge");
12105
+ const mapPatternSlug = flagString(flags, "map-pattern") ?? flagString(flags, "hosted-pattern");
12106
+ if (mapPatternSlug) {
12107
+ const registryClient = new RegistryClient({
12108
+ cacheDir: join32(workspaceInfo.appRoot, ".decantr", "cache")
12109
+ });
12110
+ const candidates = await loadPatternDiscoveryCandidates(registryClient);
12111
+ const candidate = findPatternCandidateBySlug(candidates, mapPatternSlug);
12112
+ if (!candidate) {
12113
+ const suggestions = rankPatternCandidates({ query: mapPatternSlug, limit: 5 }, candidates);
12114
+ console.error(error2(`Could not find pattern "${mapPatternSlug}" to map into local law.`));
12115
+ if (suggestions.length > 0) {
12116
+ console.error(dim3("Closest registry patterns:"));
12117
+ for (const suggestion of suggestions) {
12118
+ const slug2 = suggestion.candidate.slug || suggestion.candidate.id;
12119
+ console.error(dim3(` ${slug2} - ${suggestion.candidate.name ?? slug2}`));
12120
+ }
12121
+ }
12122
+ process.exitCode = 1;
12123
+ return;
12124
+ }
12125
+ const result = writeHostedPatternMappingProposal({
12126
+ projectRoot: workspaceInfo.appRoot,
12127
+ hostedPattern: hostedPatternRefFromCandidate(candidate)
12128
+ });
12129
+ const slug = candidate.slug || candidate.id;
12130
+ console.log(
12131
+ success3(
12132
+ `${result.replacedExisting ? "Updated" : "Wrote"} hosted pattern mapping proposal: ${result.patternPath}`
12133
+ )
12134
+ );
12135
+ console.log(
12136
+ dim3(
12137
+ `Mapped registry pattern "${slug}" into local pattern "${result.localPatternId}" as advisory Hybrid law. No source files were changed.`
12138
+ )
12139
+ );
12140
+ console.log(
12141
+ dim3(
12142
+ `Fill in project-owned component paths, token/class recipes, variants, and exceptions, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
12143
+ )
12144
+ );
12145
+ return;
12146
+ }
12147
+ const wantsLocalLaw = !wantsStyleBridge || fromAudit;
12148
+ let localResult = null;
12149
+ if (wantsLocalLaw) {
12150
+ const proposal = createBrownfieldCodifyProposal({
12151
+ projectRoot: workspaceInfo.appRoot,
12152
+ detected,
12153
+ essence,
12154
+ fromAudit
12155
+ });
12156
+ localResult = writeBrownfieldCodifyProposal(workspaceInfo.appRoot, proposal);
12157
+ }
12158
+ let styleBridgeResult = null;
12159
+ if (wantsStyleBridge) {
12160
+ const styling = scanStyling(workspaceInfo.appRoot);
12161
+ styleBridgeResult = writeStyleBridgeProposal(
12162
+ workspaceInfo.appRoot,
12163
+ createStyleBridgeProposal({
12164
+ projectRoot: workspaceInfo.appRoot,
12165
+ detected,
12166
+ essence,
12167
+ styling
12168
+ })
12169
+ );
12170
+ }
12171
+ if (localResult) {
12172
+ console.log(success3(`Wrote local pattern proposal: ${localResult.patternPath}`));
12173
+ console.log(success3(`Wrote local rule proposal: ${localResult.rulesPath}`));
12174
+ }
12175
+ if (styleBridgeResult) {
12176
+ console.log(success3(`Wrote style bridge proposal: ${styleBridgeResult}`));
12177
+ }
12178
+ if (fromAudit && localResult) {
11223
12179
  console.log(
11224
12180
  dim3(
11225
12181
  "Proposal includes source-derived component candidates, starter mechanical rules, and Hybrid authority guidance."
@@ -11228,7 +12184,7 @@ async function cmdCodifyWorkflow(args) {
11228
12184
  }
11229
12185
  console.log(
11230
12186
  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)}\`.`
12187
+ `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
12188
  )
11233
12189
  );
11234
12190
  }
@@ -11277,13 +12233,14 @@ ${BOLD9}decantr${RESET16} \u2014 Design intelligence for AI-generated UI
11277
12233
 
11278
12234
  ${BOLD9}Usage:${RESET16}
11279
12235
  decantr setup [--project <path>]
12236
+ decantr scan [--project <path>] [--json]
11280
12237
  decantr new <name> [--blueprint=X] [--archetype=X] [--theme=X] [--workflow=greenfield] [--adoption=decantr-css] [--telemetry]
11281
12238
  decantr adopt [--project <path>] [--base-url <url>] [--evidence] [--ci] [--no-packs] [--yes]
11282
12239
  decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]
11283
12240
  decantr verify [--project <path>] [--brownfield] [--local-patterns] [health options]
11284
12241
  decantr ci [--project <path>] [--workspace] [--fail-on error|warn|none]
11285
12242
  decantr doctor [--project <path>] [--workspace] [--json]
11286
- decantr codify [--from-audit] [--accept] [--project <path>]
12243
+ decantr codify [--from-audit] [--style-bridge] [--map-pattern <slug>] [--accept] [--project <path>]
11287
12244
  decantr studio [--port 4319] [--host 127.0.0.1] [--report decantr-health.json] [--workspace]
11288
12245
 
11289
12246
  ${BOLD9}Advanced primitives:${RESET16}
@@ -11353,6 +12310,7 @@ ${BOLD9}Init Options:${RESET16}
11353
12310
 
11354
12311
  ${BOLD9}Commands:${RESET16}
11355
12312
  ${cyan3("setup")} Detect project state and recommend the right Decantr workflow
12313
+ ${cyan3("scan")} Read-only Brownfield reconnaissance; no files written
11356
12314
  ${cyan3("new")} Create a new greenfield workspace and bootstrap the available starter adapter
11357
12315
  ${cyan3("adopt")} Brownfield one-liner: analyze, attach, verify, and show next steps
11358
12316
  ${cyan3("task")} Prepare route/task context, local law, evidence, and changed-file impact for an AI coding assistant
@@ -11396,6 +12354,8 @@ ${BOLD9}Advanced commands:${RESET16}
11396
12354
 
11397
12355
  ${BOLD9}Examples:${RESET16}
11398
12356
  decantr setup
12357
+ decantr scan
12358
+ decantr scan --json
11399
12359
  decantr new my-app --blueprint=carbon-ai-portal
11400
12360
  decantr adopt --yes
11401
12361
  decantr adopt --project apps/web --yes
@@ -11407,6 +12367,7 @@ ${BOLD9}Examples:${RESET16}
11407
12367
  decantr ci --project apps/web
11408
12368
  decantr ci init --project apps/web
11409
12369
  decantr codify --from-audit
12370
+ decantr codify --map-pattern hero --project apps/web
11410
12371
  decantr codify --accept
11411
12372
  decantr content check --ci --fail-on error
11412
12373
  decantr magic "AI chatbot with dark cyber theme \u2014 bold and futuristic"
@@ -11454,6 +12415,7 @@ ${BOLD9}Workflow Model:${RESET16}
11454
12415
  ${cyan3("Greenfield blueprint")} decantr new my-app --blueprint=X --workflow=greenfield --adoption=decantr-css
11455
12416
  ${cyan3("Greenfield contract")} decantr init --workflow=greenfield --adoption=contract-only
11456
12417
  ${cyan3("Brownfield adoption")} decantr adopt --yes
12418
+ ${cyan3("Brownfield preview")} decantr scan -> decantr adopt --yes
11457
12419
  ${cyan3("Brownfield monorepo")} decantr adopt --project apps/web --yes
11458
12420
  ${cyan3("Daily LLM work")} decantr task <route> "<change>" -> decantr verify --brownfield --local-patterns
11459
12421
  ${cyan3("Project-owned law")} decantr codify --from-audit -> edit proposal -> decantr codify --accept
@@ -11482,6 +12444,28 @@ ${BOLD9}Examples:${RESET16}
11482
12444
  decantr rules apply --project=apps/web
11483
12445
  `);
11484
12446
  }
12447
+ function cmdScanHelp() {
12448
+ console.log(`
12449
+ ${BOLD9}decantr scan${RESET16} \u2014 Read-only Brownfield reconnaissance
12450
+
12451
+ ${BOLD9}Usage:${RESET16}
12452
+ decantr scan [--project <path>] [--json]
12453
+
12454
+ ${BOLD9}Options:${RESET16}
12455
+ --project App path inside a workspace/monorepo
12456
+ --json Emit the ScanReportV1 JSON to stdout
12457
+
12458
+ ${BOLD9}Behavior:${RESET16}
12459
+ Reads local project files, detects frontend framework/routes/styling/static-hosting signals,
12460
+ and prints a terminal report. It does not write .decantr files, install dependencies,
12461
+ build the app, execute scripts, upload source, or open pull requests.
12462
+
12463
+ ${BOLD9}Examples:${RESET16}
12464
+ decantr scan
12465
+ decantr scan --project apps/web
12466
+ decantr scan --json
12467
+ `);
12468
+ }
11485
12469
  function isCommandHelpRequest(args) {
11486
12470
  return args[1] === "help" || args.slice(1).some((arg) => arg === "--help" || arg === "-h");
11487
12471
  }
@@ -11703,15 +12687,19 @@ ${BOLD9}Examples:${RESET16}
11703
12687
  }
11704
12688
  function cmdCodifyHelp() {
11705
12689
  console.log(`
11706
- ${BOLD9}decantr codify${RESET16} \u2014 Propose or accept project-owned Brownfield UI patterns and rules
12690
+ ${BOLD9}decantr codify${RESET16} \u2014 Propose or accept project-owned Brownfield UI law and style bridges
11707
12691
 
11708
12692
  ${BOLD9}Usage:${RESET16}
11709
- decantr codify [--from-audit] [--project <path>]
12693
+ decantr codify [--from-audit] [--style-bridge] [--project <path>]
12694
+ decantr codify --map-pattern <registry-pattern-slug> [--project <path>]
11710
12695
  decantr codify --accept [--project <path>]
11711
12696
 
11712
12697
  ${BOLD9}Examples:${RESET16}
11713
12698
  decantr codify
11714
12699
  decantr codify --from-audit
12700
+ decantr codify --style-bridge
12701
+ decantr codify --from-audit --style-bridge
12702
+ decantr codify --map-pattern hero --project apps/web
11715
12703
  decantr codify --accept
11716
12704
  decantr verify --brownfield --local-patterns
11717
12705
  `);
@@ -11737,6 +12725,9 @@ function printCommandHelp(command, args) {
11737
12725
  case "setup":
11738
12726
  cmdSetupHelp();
11739
12727
  return true;
12728
+ case "scan":
12729
+ cmdScanHelp();
12730
+ return true;
11740
12731
  case "adopt":
11741
12732
  cmdAdoptHelp();
11742
12733
  return true;
@@ -11794,10 +12785,10 @@ async function main() {
11794
12785
  if (command === "--version" || command === "-v" || command === "version") {
11795
12786
  try {
11796
12787
  const here = dirname6(fileURLToPath3(import.meta.url));
11797
- const candidates = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
12788
+ const candidates = [join32(here, "..", "package.json"), join32(here, "..", "..", "package.json")];
11798
12789
  for (const candidate of candidates) {
11799
- if (existsSync29(candidate)) {
11800
- const pkg = JSON.parse(readFileSync22(candidate, "utf-8"));
12790
+ if (existsSync30(candidate)) {
12791
+ const pkg = JSON.parse(readFileSync23(candidate, "utf-8"));
11801
12792
  if (pkg.version) {
11802
12793
  console.log(pkg.version);
11803
12794
  return;
@@ -11820,6 +12811,10 @@ async function main() {
11820
12811
  await cmdSetupWorkflow(args);
11821
12812
  break;
11822
12813
  }
12814
+ case "scan": {
12815
+ await cmdScanWorkflow(args);
12816
+ break;
12817
+ }
11823
12818
  case "adopt": {
11824
12819
  await cmdAdoptWorkflow(args);
11825
12820
  break;
@@ -11935,7 +12930,7 @@ async function main() {
11935
12930
  break;
11936
12931
  }
11937
12932
  case "upgrade": {
11938
- const { cmdUpgrade } = await import("./upgrade-7ZYWR2GH.js");
12933
+ const { cmdUpgrade } = await import("./upgrade-WBFE6EN7.js");
11939
12934
  const { flags } = parseLooseArgs(args);
11940
12935
  const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
11941
12936
  if (!workspaceInfo) break;
@@ -11950,7 +12945,7 @@ async function main() {
11950
12945
  `${YELLOW12}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11951
12946
  );
11952
12947
  }
11953
- const { cmdHeal } = await import("./heal-2UCSPRTK.js");
12948
+ const { cmdHeal } = await import("./heal-IRIDB7IZ.js");
11954
12949
  const { flags } = parseLooseArgs(args);
11955
12950
  const workspaceInfo = resolveWorkflowProject(flags, "check");
11956
12951
  if (!workspaceInfo) break;
@@ -11975,7 +12970,7 @@ async function main() {
11975
12970
  const { flags } = parseLooseArgs(args);
11976
12971
  const workspaceInfo = resolveWorkflowProject(flags, "health");
11977
12972
  if (!workspaceInfo) break;
11978
- const { cmdHealth, parseHealthArgs } = await import("./health-ADHNLMX3.js");
12973
+ const { cmdHealth, parseHealthArgs } = await import("./health-B4W7UJBZ.js");
11979
12974
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
11980
12975
  } catch (e) {
11981
12976
  console.error(error2(e.message));
@@ -12003,7 +12998,7 @@ async function main() {
12003
12998
  cmdStudioHelp();
12004
12999
  break;
12005
13000
  }
12006
- const { cmdStudio, parseStudioArgs } = await import("./studio-GZFCCVSO.js");
13001
+ const { cmdStudio, parseStudioArgs } = await import("./studio-JOEECLI6.js");
12007
13002
  await cmdStudio(process.cwd(), parseStudioArgs(args));
12008
13003
  } catch (e) {
12009
13004
  console.error(error2(e.message));
@@ -12017,7 +13012,7 @@ async function main() {
12017
13012
  cmdWorkspaceHelp();
12018
13013
  break;
12019
13014
  }
12020
- const { cmdWorkspace } = await import("./workspace-YYCRXJNB.js");
13015
+ const { cmdWorkspace } = await import("./workspace-7RU77ZZW.js");
12021
13016
  await cmdWorkspace(process.cwd(), args);
12022
13017
  } catch (e) {
12023
13018
  console.error(error2(e.message));
@@ -12336,7 +13331,7 @@ async function main() {
12336
13331
  break;
12337
13332
  }
12338
13333
  if (packType === "page" && route && !id) {
12339
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
13334
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join32(process.cwd(), "decantr.essence.json");
12340
13335
  id = resolvePagePackIdForRoute(resolvedPath, route);
12341
13336
  }
12342
13337
  await printHostedSelectedExecutionPack(