@decantr/cli 2.12.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.
package/README.md CHANGED
@@ -14,10 +14,12 @@ npm install -D @decantr/cli
14
14
  Or run it without installing:
15
15
 
16
16
  ```bash
17
+ npx @decantr/cli scan
17
18
  npx @decantr/cli new my-app --blueprint=esports-hq
18
19
  ```
19
20
 
20
21
  Use `decantr setup` when you are unsure which path applies. It detects whether the repo is empty, already attached, or a Brownfield app and recommends the right entry path.
22
+ Use `decantr scan` when you want a zero-commit Brownfield preview. It reads local files, detects framework/routes/styling/static-hosting/assistant-rule signals, prints a terminal report, and writes no `.decantr` files or report artifacts. Add `--json` when automation needs the `ScanReportV1` payload.
21
23
  Use `decantr new` for a greenfield workspace in a fresh directory. With a blueprint/archetype it uses the runnable adapter and Decantr CSS; without registry content it creates a contract-only workspace unless you explicitly pass `--adoption=decantr-css`.
22
24
  Use `decantr adopt` when you already have an app and want Decantr governance without adopting a blueprint. Brownfield attach is proposal-driven: Decantr inventories the app, writes an observed essence proposal, hydrates hosted execution packs when online, and only applies the contract when you explicitly accept or merge it.
23
25
  Use `decantr doctor` when the next step is unclear, `decantr task` before asking an LLM to modify a route, `decantr verify` after the edit, and `decantr ci` in required automation. Use `decantr codify --from-audit --style-bridge` when you want project-owned UI patterns, local rules, and token/class bridge mappings such as button/card/shell/theme standards to appear in future task context and verification. Once accepted, that local law is the first Hybrid lane: the app still owns source and styling, but Decantr treats accepted local patterns, rules, and style bridge mappings as project authority.
@@ -41,11 +43,14 @@ Explicit workflow/adoption flags:
41
43
 
42
44
  ```bash
43
45
  decantr setup
46
+ decantr scan
47
+ decantr scan --project apps/web --json
44
48
  decantr adopt --yes
45
49
  decantr doctor
46
50
  decantr ci --fail-on error
47
51
  decantr ci init
48
52
  decantr codify --from-audit --style-bridge
53
+ decantr codify --map-pattern hero
49
54
  decantr codify --accept
50
55
  decantr task /feed "add saved recipe actions"
51
56
  decantr verify --brownfield --local-patterns
@@ -76,16 +81,18 @@ pnpm exec decantr workspace list
76
81
  pnpm exec decantr adopt --project apps/web --yes
77
82
  pnpm exec decantr doctor --project apps/web
78
83
  pnpm exec decantr codify --from-audit --style-bridge --project apps/web
84
+ pnpm exec decantr codify --map-pattern hero --project apps/web
79
85
  pnpm exec decantr ci init --project apps/web
80
86
  ```
81
87
 
82
88
  Assistant rule integration is preview-first: `--assistant-bridge=preview` writes `.decantr/context/assistant-bridge.md`, `decantr rules preview` prints the bridge, and `--assistant-bridge=apply` or `decantr rules apply` mutates supported rule files with idempotent marked blocks.
83
89
 
84
- Brownfield analysis also writes `.decantr/doctrine-map.json`, a ranked source-precedence map across security/data, architecture, design-system, workflow/CI, feature/business, assistant-specific, stale, and unsafe-to-cite evidence. It also writes `.decantr/brownfield-intelligence.json`, `.decantr/theme-inventory.json`, and `.decantr/enrichment-backlog.md`. The proposal groups routes into observed semantic domains such as auth, RBAC, billing, reporting, facilities, settings, and public surfaces across Next App/Pages Router, React Router, Angular Router, SvelteKit, Vue Router, and Nuxt file routes. Existing styling systems such as Tailwind, Bootstrap, MUI, Chakra, plain CSS, and Decantr CSS are observed as evidence instead of replaced. Theme variants are observed in the theme inventory without changing Essence V4. `decantr codify --from-audit` proposes `.decantr/local-patterns.proposal.json` and `.decantr/rules.proposal.json` with Hybrid authority guidance and source-derived button/card class hints; `decantr codify --style-bridge` proposes `.decantr/style-bridge.proposal.json`, mapping Decantr intent to project-owned tokens/classes without requiring `@decantr/css`. After review, `decantr codify --accept` promotes whichever proposals exist. `decantr doctor` reports whether the app is contract-only, Hybrid local law, style bridge, Decantr CSS, or Hybrid composition. `decantr task` prints that authority block and warns before mixing runtimes or adding Decantr CSS to a non-Decantr-CSS app. `decantr suggest --from-code` surfaces accepted local patterns and style bridge mappings from the app root or selected `--project`, and `decantr ci` prints accepted local-rule findings plus style bridge status in text, markdown, and JSON reports. `decantr verify --brownfield --local-patterns` uses the Brownfield guard layer plus accepted local law to flag actionable missing doctrine coverage, unsafe context, missing assistant bridges, style drift, raw local-rule violations, and unsafe defaults without treating current database migrations as stale docs.
90
+ `decantr scan` is different from the mutating Brownfield primitives: it is look-don't-touch reconnaissance for fit, route/style evidence, GitHub Pages hints, and next-command guidance. `decantr analyze` writes `.decantr/doctrine-map.json`, a ranked source-precedence map across security/data, architecture, design-system, workflow/CI, feature/business, assistant-specific, stale, and unsafe-to-cite evidence. It also writes `.decantr/brownfield-intelligence.json`, `.decantr/theme-inventory.json`, and `.decantr/enrichment-backlog.md`. The proposal groups routes into observed semantic domains such as auth, RBAC, billing, reporting, facilities, settings, and public surfaces across Next App/Pages Router, React Router, Angular Router, SvelteKit, Vue Router, and Nuxt file routes. Existing styling systems such as Tailwind, Bootstrap, MUI, Chakra, plain CSS, and Decantr CSS are observed as evidence instead of replaced. Theme variants are observed in the theme inventory without changing Essence V4. `decantr codify --from-audit` proposes `.decantr/local-patterns.proposal.json` and `.decantr/rules.proposal.json` with Hybrid authority guidance, source-derived button/card/form/theme evidence, variant hints, and confidence tiers; `decantr codify --style-bridge` proposes `.decantr/style-bridge.proposal.json`, mapping Decantr intent to project-owned tokens/classes without requiring `@decantr/css`; `decantr codify --map-pattern <slug>` maps a hosted or bundled registry pattern into an advisory local-law proposal without changing source. After review, `decantr codify --accept` promotes whichever proposals exist. `decantr doctor` reports whether the app is contract-only, Hybrid local law, style bridge, Decantr CSS, or Hybrid composition. `decantr task` prints that authority block and warns before mixing runtimes or adding Decantr CSS to a non-Decantr-CSS app. `decantr suggest --from-code` surfaces accepted local patterns and style bridge mappings from the app root or selected `--project`, and `decantr ci` prints accepted local-rule findings plus style bridge status in text, markdown, and JSON reports. `decantr verify --brownfield --local-patterns` uses the Brownfield guard layer plus accepted local law to flag actionable missing doctrine coverage, unsafe context, missing assistant bridges, style drift, raw local-rule violations, and unsafe defaults without treating current database migrations as stale docs.
85
91
 
86
92
  ## What It Does
87
93
 
88
94
  - scaffolds Decantr projects from blueprints, archetypes, or prompts
95
+ - previews existing apps with read-only Brownfield scan reports
89
96
  - guides users through human workflow commands: setup, adopt, doctor, task, verify, ci, and codify
90
97
  - supports explicit workflow lanes: greenfield blueprint, greenfield contract-only, brownfield adoption, Hybrid local law, Hybrid style bridge, Hybrid Decantr CSS, and hybrid composition
91
98
  - generates execution-pack context files for AI coding assistants
@@ -99,7 +106,7 @@ Brownfield analysis also writes `.decantr/doctrine-map.json`, a ranked source-pr
99
106
 
100
107
  ## Security And Permissions
101
108
 
102
- The CLI is intentionally a local project inspector and artifact writer. It reads selected project/workspace files, package manifests, routing/style/config files, `.decantr` artifacts, and Decantr cache/config files. It writes `decantr.essence.json`, `DECANTR.md`, `.decantr/*`, generated context packs, optional CI workflows/snippets, optional style/export files, and auth/telemetry config only when explicitly requested.
109
+ The CLI is intentionally a local project inspector and artifact writer. It reads selected project/workspace files, package manifests, routing/style/config files, `.decantr` artifacts, and Decantr cache/config files. It writes `decantr.essence.json`, `DECANTR.md`, `.decantr/*`, generated context packs, optional CI workflows/snippets, optional style/export files, and auth/telemetry config only when explicitly requested. `decantr scan` is the exception by design: it reads and prints only, and does not create `.decantr`, save reports, upload source, run package scripts, or install dependencies.
103
110
 
104
111
  Telemetry is disabled by default. Hosted registry, hosted pack hydration, hosted critique/audit, and browser evidence are explicit command paths; screenshots and Evidence Bundles stay local unless a hosted workflow is invoked. Release audits prove the installed package with `npm pack --dry-run --json`. See [security permissions](https://decantr.ai/reference/security-permissions.md).
105
112
 
@@ -107,12 +114,16 @@ Telemetry is disabled by default. Hosted registry, hosted pack hydration, hosted
107
114
 
108
115
  ```bash
109
116
  decantr setup
117
+ decantr scan
118
+ decantr scan --project apps/web
119
+ decantr scan --json
110
120
  decantr new my-app --blueprint=esports-hq
111
121
  decantr adopt --yes
112
122
  decantr adopt --project apps/web --yes
113
123
  decantr doctor
114
124
  decantr doctor --project apps/web
115
125
  decantr codify --from-audit --style-bridge
126
+ decantr codify --map-pattern hero --project apps/web
116
127
  decantr codify --accept
117
128
  decantr task /feed "add saved recipe actions"
118
129
  decantr verify --brownfield --local-patterns
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-SWPAAAO4.js";
3
- import "./chunk-IQZCIMQJ.js";
4
- import "./chunk-F6SWDGKO.js";
5
- import "./chunk-PHRVC575.js";
6
- import "./chunk-CAKQWTZS.js";
2
+ import "./chunk-5MZH6XXQ.js";
3
+ import "./chunk-SIDKK73N.js";
4
+ import "./chunk-YBSBAJ3E.js";
5
+ import "./chunk-3A2DLR47.js";
6
+ import "./chunk-MNZKOZW7.js";
@@ -3,7 +3,7 @@ import {
3
3
  sendProjectHealthCiFailedTelemetry,
4
4
  sendProjectHealthPromptTelemetry,
5
5
  sendProjectHealthReportTelemetry
6
- } from "./chunk-CAKQWTZS.js";
6
+ } from "./chunk-MNZKOZW7.js";
7
7
 
8
8
  // src/commands/health.ts
9
9
  import { execFileSync } from "child_process";
@@ -91,8 +91,10 @@ function listWorkspaceAppCandidates(workspaceRoot) {
91
91
  }
92
92
  function resolveWorkspaceInfo(cwd, projectArg) {
93
93
  const absoluteCwd = resolve(cwd);
94
- const workspaceRoot = findWorkspaceRoot(absoluteCwd) ?? absoluteCwd;
95
- const appRoot = projectArg ? resolve(isAbsolute(projectArg) ? "/" : workspaceRoot, projectArg) : absoluteCwd;
94
+ const appRoot = projectArg ? resolve(
95
+ isAbsolute(projectArg) ? projectArg : join(findWorkspaceRoot(absoluteCwd) ?? absoluteCwd, projectArg)
96
+ ) : absoluteCwd;
97
+ const workspaceRoot = projectArg && isAbsolute(projectArg) ? findWorkspaceRoot(appRoot) ?? appRoot : findWorkspaceRoot(absoluteCwd) ?? absoluteCwd;
96
98
  const appCandidates = listWorkspaceApps(workspaceRoot);
97
99
  const projectScope = workspaceRoot !== appRoot || appCandidates.length > 0 ? "workspace-app" : "single-app";
98
100
  const requiresProjectSelection = !projectArg && workspaceRoot === absoluteCwd && appCandidates.length > 0;
@@ -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-F6SWDGKO.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-PHRVC575.js";
32
+ } from "./chunk-3A2DLR47.js";
33
33
  import {
34
34
  buildGuardRegistryContext,
35
35
  createDoctrineMap,
@@ -46,7 +46,7 @@ import {
46
46
  sendCliCommandTelemetry,
47
47
  sendNewProjectCompletedTelemetry,
48
48
  writeDoctrineMap
49
- } from "./chunk-CAKQWTZS.js";
49
+ } from "./chunk-MNZKOZW7.js";
50
50
 
51
51
  // src/index.ts
52
52
  import { existsSync as existsSync30, mkdirSync as mkdirSync17, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync20 } from "fs";
@@ -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
@@ -3327,6 +3328,22 @@ function createBrownfieldCodifyProposal(input) {
3327
3328
  componentPaths: evidence.buttonComponents,
3328
3329
  decide: "Define primary, secondary, tertiary, destructive, icon-only, disabled, and loading button variants from this app.",
3329
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
+ },
3330
3347
  evidence: evidence.buttonComponents.length ? evidence.buttonComponents : evidence.buttonClassHints.length ? evidence.buttonClassHints : [
3331
3348
  "No obvious Button wrapper found yet. Add the project-owned wrapper path before strict enforcement."
3332
3349
  ],
@@ -3340,6 +3357,22 @@ function createBrownfieldCodifyProposal(input) {
3340
3357
  componentPaths: evidence.cardComponents,
3341
3358
  decide: "Define the canonical card background, border, radius, shadow, padding, density, and hover treatment.",
3342
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
+ },
3343
3376
  evidence: evidence.cardComponents.length ? evidence.cardComponents : [
3344
3377
  "No obvious Card wrapper found yet. Add the project-owned wrapper path or class recipe."
3345
3378
  ],
@@ -3352,6 +3385,24 @@ function createBrownfieldCodifyProposal(input) {
3352
3385
  appliesTo: ["routes", "layouts", "navigation shells", "scroll containers"],
3353
3386
  componentPaths: evidence.shellComponents,
3354
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
+ },
3355
3406
  evidence: evidence.shellComponents.length ? evidence.shellComponents : ["Add root layout, shell, or app frame files that establish route chrome and spacing."],
3356
3407
  forbiddenAlternatives: [
3357
3408
  "Each page inventing independent max-width, padding, or sticky nav rules."
@@ -3364,6 +3415,20 @@ function createBrownfieldCodifyProposal(input) {
3364
3415
  appliesTo: ["inputs", "selects", "textareas", "validation messages", "form actions"],
3365
3416
  componentPaths: evidence.formComponents,
3366
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
+ },
3367
3432
  evidence: evidence.formComponents.length ? evidence.formComponents : ["Add form field wrapper paths and validation examples."],
3368
3433
  forbiddenAlternatives: [
3369
3434
  "Unlabeled one-off inputs or validation states that do not match the app standard."
@@ -3376,6 +3441,20 @@ function createBrownfieldCodifyProposal(input) {
3376
3441
  appliesTo: ["theme toggles", "mode-specific classes", "brand variants", "tenant variants"],
3377
3442
  componentPaths: evidence.themeComponents,
3378
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
+ },
3379
3458
  evidence: evidence.themeComponents.length ? evidence.themeComponents : ["If the app has dark/light or brand variants, add the toggles/providers here."],
3380
3459
  forbiddenAlternatives: [
3381
3460
  "Component-local theme forks that bypass shared theme providers or tokens."
@@ -3467,6 +3546,107 @@ function writeBrownfieldCodifyProposal(projectRoot, proposal) {
3467
3546
  `, "utf-8");
3468
3547
  return { patternPath, rulesPath };
3469
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
+ }
3470
3650
  function acceptBrownfieldLocalLaw(projectRoot) {
3471
3651
  const patternProposal = readJsonFile(localPatternsProposalPath(projectRoot));
3472
3652
  const ruleProposal = readJsonFile(localRulesProposalPath(projectRoot));
@@ -3509,11 +3689,17 @@ function validateLocalLaw(projectRoot) {
3509
3689
  const paths = Array.isArray(pattern.componentPaths) ? pattern.componentPaths : [];
3510
3690
  const evidence = Array.isArray(pattern.evidence) ? pattern.evidence : [];
3511
3691
  const todoEvidence = Array.isArray(pattern.evidenceToCollect) ? pattern.evidenceToCollect : [];
3692
+ const hostedRefs = Array.isArray(pattern.hostedPatternRefs) ? pattern.hostedPatternRefs : [];
3512
3693
  if (id && paths.length === 0 && evidence.length === 0 && todoEvidence.length > 0) {
3513
3694
  warnings.push(
3514
3695
  `Local pattern ${id} still reads like a TODO; add concrete component paths or evidence.`
3515
3696
  );
3516
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
+ }
3517
3703
  }
3518
3704
  }
3519
3705
  if (ruleManifest && !Array.isArray(ruleManifest.rules)) {
@@ -3535,7 +3721,10 @@ function createLocalLawTaskSummary(projectRoot) {
3535
3721
  const patterns = (patternPack?.patterns ?? []).map((pattern) => ({
3536
3722
  id: typeof pattern.id === "string" ? pattern.id : "unknown",
3537
3723
  role: typeof pattern.role === "string" ? pattern.role : null,
3538
- 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)) : []
3539
3728
  }));
3540
3729
  const rules = (ruleManifest?.rules ?? []).map((rule) => ({
3541
3730
  id: rule.id,
@@ -3653,6 +3842,50 @@ function summarizeSourceEvidence(projectRoot, files) {
3653
3842
  formComponents: byName(["input", "field", "form", "select", "textarea"]),
3654
3843
  shellComponents,
3655
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
+ ]),
3656
3889
  buttonClassHints: collectClassHints(projectRoot, files, [
3657
3890
  "button",
3658
3891
  "btn",
@@ -3666,6 +3899,70 @@ function summarizeSourceEvidence(projectRoot, files) {
3666
3899
  cardClassHints: collectClassHints(projectRoot, files, ["card", "panel", "surface", "tile"])
3667
3900
  };
3668
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
+ }
3669
3966
  function collectClassHints(projectRoot, files, terms) {
3670
3967
  const hints = /* @__PURE__ */ new Map();
3671
3968
  const wantsButton = terms.some(
@@ -3760,6 +4057,9 @@ function lineColumnAt(contents, index) {
3760
4057
  column: lines[lines.length - 1].length + 1
3761
4058
  };
3762
4059
  }
4060
+ function escapeRegExp(value) {
4061
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4062
+ }
3763
4063
  function lineAt(contents, line) {
3764
4064
  return contents.split(/\r?\n/)[line - 1] ?? "";
3765
4065
  }
@@ -4225,6 +4525,9 @@ function formatLocalLawText(summary, health) {
4225
4525
  lines.push(
4226
4526
  ` Patterns: ${summary.patternsPresent ? "present" : "missing"} | Rules: ${summary.rulesPresent ? "present" : "missing"}`
4227
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
+ );
4228
4531
  lines.push(` Findings: ${summary.errorCount} error(s), ${summary.warnCount} warning(s)`);
4229
4532
  for (const warning of summary.warnings.slice(0, 5)) {
4230
4533
  lines.push(` ${DIM3}[WARN] ${warning}${RESET3}`);
@@ -4252,6 +4555,9 @@ function formatStyleBridgeText(summary) {
4252
4555
  lines.push(
4253
4556
  ` Present: ${summary.present ? "yes" : "no"} | Mappings: ${summary.mappingCount} | Styling: ${summary.stylingApproach ?? "unknown"}`
4254
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
+ );
4255
4561
  if (summary.themeModes.length > 0) {
4256
4562
  lines.push(` Theme modes: ${summary.themeModes.join(", ")}`);
4257
4563
  }
@@ -4276,6 +4582,9 @@ function formatLocalLawMarkdown(summary, health) {
4276
4582
  lines.push(
4277
4583
  `Patterns: **${summary.patternsPresent ? "present" : "missing"}** \xB7 Rules: **${summary.rulesPresent ? "present" : "missing"}**`
4278
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
+ );
4279
4588
  lines.push("");
4280
4589
  lines.push(`Findings: **${summary.errorCount} error(s), ${summary.warnCount} warning(s)**`);
4281
4590
  if (summary.warnings.length > 0) {
@@ -4303,6 +4612,10 @@ function formatStyleBridgeMarkdown(summary) {
4303
4612
  lines.push(
4304
4613
  `Present: **${summary.present ? "yes" : "no"}** \xB7 Mappings: **${summary.mappingCount}** \xB7 Styling: **${summary.stylingApproach ?? "unknown"}**`
4305
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
+ );
4306
4619
  if (summary.themeModes.length > 0) {
4307
4620
  lines.push("", `Theme modes: ${summary.themeModes.map((mode) => `\`${mode}\``).join(", ")}`);
4308
4621
  }
@@ -9270,6 +9583,25 @@ function patternCandidateFromRegistryItem(item, source) {
9270
9583
  { source, slug }
9271
9584
  );
9272
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
+ }
9273
9605
  function readSuggestCodeContext(projectRoot, route, file) {
9274
9606
  const pieces = [];
9275
9607
  if (file) {
@@ -10936,7 +11268,12 @@ function resolveWorkflowProject(flags, commandName = "command", options = {}) {
10936
11268
  }
10937
11269
  if (projectArg && options.requireAppCandidate && workspaceInfo.appCandidates.length > 0) {
10938
11270
  const normalizedProject = normalizedProjectPath(projectArg);
10939
- 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;
10940
11277
  const forcePackage = flagBoolean(flags, "force-package") || flagBoolean(flags, "allow-package") || flagBoolean(flags, "force");
10941
11278
  if (!knownCandidate && !forcePackage && !options.allowPackageProject) {
10942
11279
  console.error(
@@ -10969,6 +11306,101 @@ function printWorkflowPlan(title, steps) {
10969
11306
  }
10970
11307
  console.log("");
10971
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
+ }
10972
11404
  async function cmdSetupWorkflow(args) {
10973
11405
  const { flags } = parseLooseArgs(args);
10974
11406
  const projectArg = flagString(flags, "project");
@@ -11148,7 +11580,7 @@ async function cmdAdoptWorkflow(args) {
11148
11580
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
11149
11581
  }
11150
11582
  if (runVerify) {
11151
- const { cmdHealth } = await import("./health-DBCUR6VQ.js");
11583
+ const { cmdHealth } = await import("./health-B4W7UJBZ.js");
11152
11584
  await cmdHealth(projectRoot, {
11153
11585
  browser: runBrowser,
11154
11586
  browserBaseUrl: baseUrl,
@@ -11219,7 +11651,7 @@ async function cmdVerifyWorkflow(args) {
11219
11651
  return;
11220
11652
  }
11221
11653
  if (workspaceMode) {
11222
- const { cmdWorkspace } = await import("./workspace-BCA5RCHN.js");
11654
+ const { cmdWorkspace } = await import("./workspace-7RU77ZZW.js");
11223
11655
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
11224
11656
  return;
11225
11657
  }
@@ -11252,7 +11684,7 @@ async function cmdVerifyWorkflow(args) {
11252
11684
  }
11253
11685
  let guardExitCode;
11254
11686
  if (brownfield) {
11255
- const { cmdHeal, collectCheckIssues } = await import("./heal-WMSAX4LU.js");
11687
+ const { cmdHeal, collectCheckIssues } = await import("./heal-IRIDB7IZ.js");
11256
11688
  if (quietOutput) {
11257
11689
  const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
11258
11690
  guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
@@ -11262,7 +11694,7 @@ async function cmdVerifyWorkflow(args) {
11262
11694
  process.exitCode = void 0;
11263
11695
  }
11264
11696
  }
11265
- const { cmdHealth, parseHealthArgs } = await import("./health-DBCUR6VQ.js");
11697
+ const { cmdHealth, parseHealthArgs } = await import("./health-B4W7UJBZ.js");
11266
11698
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
11267
11699
  if (localPatterns) {
11268
11700
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -11284,6 +11716,9 @@ async function cmdVerifyWorkflow(args) {
11284
11716
  console.log(`${GREEN16}Local pattern pack found:${RESET16} ${validation.patternsPath}`);
11285
11717
  if (validation.ruleManifestPresent) {
11286
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
+ );
11287
11722
  } else {
11288
11723
  console.log(
11289
11724
  `${YELLOW12}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
@@ -11319,6 +11754,9 @@ async function cmdVerifyWorkflow(args) {
11319
11754
  console.log(
11320
11755
  `${DIM16}${styleBridge.mappingCount} mapping(s), ${styleBridge.stylingApproach ?? "unknown"} styling${styleBridge.themeModes.length > 0 ? `, themes: ${styleBridge.themeModes.join(", ")}` : ""}${RESET16}`
11321
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
+ );
11322
11760
  }
11323
11761
  if (guardExitCode && guardExitCode !== 0 && (!process.exitCode || process.exitCode === 0)) {
11324
11762
  process.exitCode = guardExitCode;
@@ -11548,10 +11986,17 @@ async function cmdTaskWorkflow(args) {
11548
11986
  }
11549
11987
  if (context.localLaw.rulesPath) {
11550
11988
  console.log(` Rules: ${cyan3(context.localLaw.rulesPath)} (${context.localLaw.ruleCount})`);
11989
+ console.log(" Enforcement: accepted local rules are the Decantr-scanned layer.");
11551
11990
  }
11552
11991
  for (const pattern of context.localLaw.patterns.slice(0, 4)) {
11553
11992
  const pathHint = pattern.componentPaths.length > 0 ? ` \u2014 ${pattern.componentPaths.slice(0, 2).join(", ")}` : "";
11554
- 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}`);
11555
12000
  }
11556
12001
  } else {
11557
12002
  console.log("");
@@ -11566,6 +12011,9 @@ async function cmdTaskWorkflow(args) {
11566
12011
  console.log(
11567
12012
  ` Bridge: ${cyan3(context.styleBridge.path)} (${context.styleBridge.mappingCount} mappings, ${context.styleBridge.stylingApproach ?? "unknown"} styling)`
11568
12013
  );
12014
+ console.log(
12015
+ " Enforcement: advisory mapping layer; accepted local rules or project lint/tests do the blocking."
12016
+ );
11569
12017
  if (context.styleBridge.themeModes.length > 0) {
11570
12018
  console.log(` Theme modes: ${context.styleBridge.themeModes.join(", ")}`);
11571
12019
  }
@@ -11605,6 +12053,8 @@ async function cmdCodifyWorkflow(args) {
11605
12053
  "discover-local-patterns",
11606
12054
  "codify-local-patterns",
11607
12055
  "style-bridge",
12056
+ "map-pattern",
12057
+ "hosted-pattern",
11608
12058
  "accept"
11609
12059
  ],
11610
12060
  "codify"
@@ -11652,6 +12102,48 @@ async function cmdCodifyWorkflow(args) {
11652
12102
  );
11653
12103
  const fromAudit = flagBoolean(flags, "from-audit") || flagBoolean(flags, "discover-local-patterns") || flagBoolean(flags, "codify-local-patterns");
11654
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
+ }
11655
12147
  const wantsLocalLaw = !wantsStyleBridge || fromAudit;
11656
12148
  let localResult = null;
11657
12149
  if (wantsLocalLaw) {
@@ -11741,13 +12233,14 @@ ${BOLD9}decantr${RESET16} \u2014 Design intelligence for AI-generated UI
11741
12233
 
11742
12234
  ${BOLD9}Usage:${RESET16}
11743
12235
  decantr setup [--project <path>]
12236
+ decantr scan [--project <path>] [--json]
11744
12237
  decantr new <name> [--blueprint=X] [--archetype=X] [--theme=X] [--workflow=greenfield] [--adoption=decantr-css] [--telemetry]
11745
12238
  decantr adopt [--project <path>] [--base-url <url>] [--evidence] [--ci] [--no-packs] [--yes]
11746
12239
  decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]
11747
12240
  decantr verify [--project <path>] [--brownfield] [--local-patterns] [health options]
11748
12241
  decantr ci [--project <path>] [--workspace] [--fail-on error|warn|none]
11749
12242
  decantr doctor [--project <path>] [--workspace] [--json]
11750
- decantr codify [--from-audit] [--style-bridge] [--accept] [--project <path>]
12243
+ decantr codify [--from-audit] [--style-bridge] [--map-pattern <slug>] [--accept] [--project <path>]
11751
12244
  decantr studio [--port 4319] [--host 127.0.0.1] [--report decantr-health.json] [--workspace]
11752
12245
 
11753
12246
  ${BOLD9}Advanced primitives:${RESET16}
@@ -11817,6 +12310,7 @@ ${BOLD9}Init Options:${RESET16}
11817
12310
 
11818
12311
  ${BOLD9}Commands:${RESET16}
11819
12312
  ${cyan3("setup")} Detect project state and recommend the right Decantr workflow
12313
+ ${cyan3("scan")} Read-only Brownfield reconnaissance; no files written
11820
12314
  ${cyan3("new")} Create a new greenfield workspace and bootstrap the available starter adapter
11821
12315
  ${cyan3("adopt")} Brownfield one-liner: analyze, attach, verify, and show next steps
11822
12316
  ${cyan3("task")} Prepare route/task context, local law, evidence, and changed-file impact for an AI coding assistant
@@ -11860,6 +12354,8 @@ ${BOLD9}Advanced commands:${RESET16}
11860
12354
 
11861
12355
  ${BOLD9}Examples:${RESET16}
11862
12356
  decantr setup
12357
+ decantr scan
12358
+ decantr scan --json
11863
12359
  decantr new my-app --blueprint=carbon-ai-portal
11864
12360
  decantr adopt --yes
11865
12361
  decantr adopt --project apps/web --yes
@@ -11871,6 +12367,7 @@ ${BOLD9}Examples:${RESET16}
11871
12367
  decantr ci --project apps/web
11872
12368
  decantr ci init --project apps/web
11873
12369
  decantr codify --from-audit
12370
+ decantr codify --map-pattern hero --project apps/web
11874
12371
  decantr codify --accept
11875
12372
  decantr content check --ci --fail-on error
11876
12373
  decantr magic "AI chatbot with dark cyber theme \u2014 bold and futuristic"
@@ -11918,6 +12415,7 @@ ${BOLD9}Workflow Model:${RESET16}
11918
12415
  ${cyan3("Greenfield blueprint")} decantr new my-app --blueprint=X --workflow=greenfield --adoption=decantr-css
11919
12416
  ${cyan3("Greenfield contract")} decantr init --workflow=greenfield --adoption=contract-only
11920
12417
  ${cyan3("Brownfield adoption")} decantr adopt --yes
12418
+ ${cyan3("Brownfield preview")} decantr scan -> decantr adopt --yes
11921
12419
  ${cyan3("Brownfield monorepo")} decantr adopt --project apps/web --yes
11922
12420
  ${cyan3("Daily LLM work")} decantr task <route> "<change>" -> decantr verify --brownfield --local-patterns
11923
12421
  ${cyan3("Project-owned law")} decantr codify --from-audit -> edit proposal -> decantr codify --accept
@@ -11946,6 +12444,28 @@ ${BOLD9}Examples:${RESET16}
11946
12444
  decantr rules apply --project=apps/web
11947
12445
  `);
11948
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
+ }
11949
12469
  function isCommandHelpRequest(args) {
11950
12470
  return args[1] === "help" || args.slice(1).some((arg) => arg === "--help" || arg === "-h");
11951
12471
  }
@@ -12171,6 +12691,7 @@ ${BOLD9}decantr codify${RESET16} \u2014 Propose or accept project-owned Brownfie
12171
12691
 
12172
12692
  ${BOLD9}Usage:${RESET16}
12173
12693
  decantr codify [--from-audit] [--style-bridge] [--project <path>]
12694
+ decantr codify --map-pattern <registry-pattern-slug> [--project <path>]
12174
12695
  decantr codify --accept [--project <path>]
12175
12696
 
12176
12697
  ${BOLD9}Examples:${RESET16}
@@ -12178,6 +12699,7 @@ ${BOLD9}Examples:${RESET16}
12178
12699
  decantr codify --from-audit
12179
12700
  decantr codify --style-bridge
12180
12701
  decantr codify --from-audit --style-bridge
12702
+ decantr codify --map-pattern hero --project apps/web
12181
12703
  decantr codify --accept
12182
12704
  decantr verify --brownfield --local-patterns
12183
12705
  `);
@@ -12203,6 +12725,9 @@ function printCommandHelp(command, args) {
12203
12725
  case "setup":
12204
12726
  cmdSetupHelp();
12205
12727
  return true;
12728
+ case "scan":
12729
+ cmdScanHelp();
12730
+ return true;
12206
12731
  case "adopt":
12207
12732
  cmdAdoptHelp();
12208
12733
  return true;
@@ -12286,6 +12811,10 @@ async function main() {
12286
12811
  await cmdSetupWorkflow(args);
12287
12812
  break;
12288
12813
  }
12814
+ case "scan": {
12815
+ await cmdScanWorkflow(args);
12816
+ break;
12817
+ }
12289
12818
  case "adopt": {
12290
12819
  await cmdAdoptWorkflow(args);
12291
12820
  break;
@@ -12401,7 +12930,7 @@ async function main() {
12401
12930
  break;
12402
12931
  }
12403
12932
  case "upgrade": {
12404
- const { cmdUpgrade } = await import("./upgrade-7ZYWR2GH.js");
12933
+ const { cmdUpgrade } = await import("./upgrade-WBFE6EN7.js");
12405
12934
  const { flags } = parseLooseArgs(args);
12406
12935
  const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
12407
12936
  if (!workspaceInfo) break;
@@ -12416,7 +12945,7 @@ async function main() {
12416
12945
  `${YELLOW12}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
12417
12946
  );
12418
12947
  }
12419
- const { cmdHeal } = await import("./heal-WMSAX4LU.js");
12948
+ const { cmdHeal } = await import("./heal-IRIDB7IZ.js");
12420
12949
  const { flags } = parseLooseArgs(args);
12421
12950
  const workspaceInfo = resolveWorkflowProject(flags, "check");
12422
12951
  if (!workspaceInfo) break;
@@ -12441,7 +12970,7 @@ async function main() {
12441
12970
  const { flags } = parseLooseArgs(args);
12442
12971
  const workspaceInfo = resolveWorkflowProject(flags, "health");
12443
12972
  if (!workspaceInfo) break;
12444
- const { cmdHealth, parseHealthArgs } = await import("./health-DBCUR6VQ.js");
12973
+ const { cmdHealth, parseHealthArgs } = await import("./health-B4W7UJBZ.js");
12445
12974
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
12446
12975
  } catch (e) {
12447
12976
  console.error(error2(e.message));
@@ -12469,7 +12998,7 @@ async function main() {
12469
12998
  cmdStudioHelp();
12470
12999
  break;
12471
13000
  }
12472
- const { cmdStudio, parseStudioArgs } = await import("./studio-L6JJQYCS.js");
13001
+ const { cmdStudio, parseStudioArgs } = await import("./studio-JOEECLI6.js");
12473
13002
  await cmdStudio(process.cwd(), parseStudioArgs(args));
12474
13003
  } catch (e) {
12475
13004
  console.error(error2(e.message));
@@ -12483,7 +13012,7 @@ async function main() {
12483
13012
  cmdWorkspaceHelp();
12484
13013
  break;
12485
13014
  }
12486
- const { cmdWorkspace } = await import("./workspace-BCA5RCHN.js");
13015
+ const { cmdWorkspace } = await import("./workspace-7RU77ZZW.js");
12487
13016
  await cmdWorkspace(process.cwd(), args);
12488
13017
  } catch (e) {
12489
13018
  console.error(error2(e.message));
@@ -1083,6 +1083,14 @@ function routeLabel(routes) {
1083
1083
  if (routes.length <= 6) return routes.join(", ");
1084
1084
  return `${routes.slice(0, 6).join(", ")} (+${routes.length - 6} more)`;
1085
1085
  }
1086
+ function routePathname(route) {
1087
+ const queryIndex = route.indexOf("?");
1088
+ if (queryIndex === -1) return route;
1089
+ return route.slice(0, queryIndex) || "/";
1090
+ }
1091
+ function declaredRouteObserved(route, observedRoutes) {
1092
+ return observedRoutes.has(route) || route.includes("?") && observedRoutes.has(routePathname(route));
1093
+ }
1086
1094
  function hasDoctrineEffect(essence, key) {
1087
1095
  const effects = essence.dna.constraints?.effects;
1088
1096
  return Boolean(effects && effects[key]);
@@ -1126,7 +1134,9 @@ function scanBrownfieldIssues(projectRoot, essence) {
1126
1134
  const declaredRoutes = essenceRoutes(essence);
1127
1135
  const observedRoutes = new Set(routes.routes.map((route) => route.path));
1128
1136
  const missingFromEssence = [...observedRoutes].filter((route) => !declaredRoutes.has(route));
1129
- const missingFromSource = [...declaredRoutes].filter((route) => !observedRoutes.has(route));
1137
+ const missingFromSource = [...declaredRoutes].filter(
1138
+ (route) => !declaredRouteObserved(route, observedRoutes)
1139
+ );
1130
1140
  if (routes.routes.length > 0 && declaredRoutes.size === 0) {
1131
1141
  issues.push({
1132
1142
  type: "error",
@@ -3780,14 +3780,36 @@ This project uses Decantr as a **contract and governance layer only**.
3780
3780
 
3781
3781
  Do not install \`@decantr/css\`, rewrite the styling system, or add generated Decantr CSS files unless the task explicitly changes the adoption mode. Preserve the existing framework styling conventions and map them into the Decantr context before changing implementation files.
3782
3782
 
3783
- Use \`.decantr/context/scaffold-pack.md\` and the matching section/page packs to understand visual intent, shell structure, and route contracts. Implement those contracts through the project's current CSS, component library, tokens, or design-system primitives.`;
3783
+ Use \`.decantr/context/scaffold-pack.md\` and the matching section/page packs to understand visual intent, shell structure, and route contracts. Implement those contracts through the project's current CSS, component library, tokens, or design-system primitives.
3784
+
3785
+ ### Interaction Requirements
3786
+
3787
+ Every pattern declares its required interactions in its page-pack \`Interactions\` checklist. A declared interaction must be implemented in source through the project's existing component library, CSS, or event-handler patterns.
3788
+
3789
+ | Declared interaction | Canonical implementation shape |
3790
+ |----------------------|--------------------------------|
3791
+ | \`animate-on-mount\` | Entrance animation class or component transition on the pattern root |
3792
+ | \`stagger-children\` | Parent stagger class or animation delay driven by child index |
3793
+ | \`keyboard-navigation\` | Arrow-key/Enter/Space handlers with visible focus state |
3794
+ | \`ripple-click\` | \`d-ripple\` or an equivalent click feedback class on the interactive surface |`;
3784
3795
  var STYLE_BRIDGE_CSS_APPROACH = `## Styling Adoption
3785
3796
 
3786
3797
  This project uses Decantr in **style-bridge** mode.
3787
3798
 
3788
3799
  Decantr may generate lightweight bridge files such as \`src/styles/tokens.css\` and \`src/styles/decantr-bridge.css\`, but \`@decantr/css\` is not required. Treat these files as a mapping layer between Decantr context and the app's existing styling system.
3789
3800
 
3790
- Preserve the current CSS framework/component library. Use Decantr tokens and bridge classes only where they clarify design intent without replacing the app's established styling conventions.`;
3801
+ Preserve the current CSS framework/component library. Use Decantr tokens and bridge classes only where they clarify design intent without replacing the app's established styling conventions.
3802
+
3803
+ ### Interaction Requirements
3804
+
3805
+ Every pattern declares its required interactions in its page-pack \`Interactions\` checklist. A declared interaction must be implemented in source through the project's existing component library, CSS, or event-handler patterns.
3806
+
3807
+ | Declared interaction | Canonical implementation shape |
3808
+ |----------------------|--------------------------------|
3809
+ | \`animate-on-mount\` | Entrance animation class or component transition on the pattern root |
3810
+ | \`stagger-children\` | Parent stagger class or animation delay driven by child index |
3811
+ | \`keyboard-navigation\` | Arrow-key/Enter/Space handlers with visible focus state |
3812
+ | \`ripple-click\` | \`d-ripple\` or an equivalent click feedback class on the interactive surface |`;
3791
3813
  function getCssApproachContent(adoptionMode) {
3792
3814
  if (adoptionMode === "contract-only") return CONTRACT_ONLY_CSS_APPROACH;
3793
3815
  if (adoptionMode === "style-bridge") return STYLE_BRIDGE_CSS_APPROACH;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createProjectHealthReport,
3
3
  listWorkspaceAppCandidates
4
- } from "./chunk-PHRVC575.js";
4
+ } from "./chunk-3A2DLR47.js";
5
5
 
6
6
  // src/commands/workspace.ts
7
7
  import { execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cmdHeal,
3
3
  collectCheckIssues
4
- } from "./chunk-CAKQWTZS.js";
4
+ } from "./chunk-MNZKOZW7.js";
5
5
  export {
6
6
  cmdHeal,
7
7
  collectCheckIssues
@@ -10,8 +10,8 @@ import {
10
10
  renderProjectHealthCiWorkflow,
11
11
  shouldFailHealth,
12
12
  writeProjectHealthCiWorkflow
13
- } from "./chunk-PHRVC575.js";
14
- import "./chunk-CAKQWTZS.js";
13
+ } from "./chunk-3A2DLR47.js";
14
+ import "./chunk-MNZKOZW7.js";
15
15
  export {
16
16
  cmdHealth,
17
17
  collectDesignTokenEvidence,
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./chunk-SWPAAAO4.js";
2
- import "./chunk-IQZCIMQJ.js";
3
- import "./chunk-F6SWDGKO.js";
4
- import "./chunk-PHRVC575.js";
5
- import "./chunk-CAKQWTZS.js";
1
+ import "./chunk-5MZH6XXQ.js";
2
+ import "./chunk-SIDKK73N.js";
3
+ import "./chunk-YBSBAJ3E.js";
4
+ import "./chunk-3A2DLR47.js";
5
+ import "./chunk-MNZKOZW7.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createWorkspaceHealthReport
3
- } from "./chunk-F6SWDGKO.js";
3
+ } from "./chunk-YBSBAJ3E.js";
4
4
  import {
5
5
  createProjectHealthReport
6
- } from "./chunk-PHRVC575.js";
6
+ } from "./chunk-3A2DLR47.js";
7
7
  import {
8
8
  sendStudioHealthRefreshedTelemetry,
9
9
  sendStudioStartedTelemetry
10
- } from "./chunk-CAKQWTZS.js";
10
+ } from "./chunk-MNZKOZW7.js";
11
11
 
12
12
  // src/commands/studio.ts
13
13
  import { readFileSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RegistryClient,
3
3
  refreshDerivedFiles
4
- } from "./chunk-IQZCIMQJ.js";
4
+ } from "./chunk-SIDKK73N.js";
5
5
 
6
6
  // src/commands/upgrade.ts
7
7
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -7,9 +7,9 @@ import {
7
7
  listWorkspaceProjects,
8
8
  parseWorkspaceArgs,
9
9
  shouldFailWorkspaceHealth
10
- } from "./chunk-F6SWDGKO.js";
11
- import "./chunk-PHRVC575.js";
12
- import "./chunk-CAKQWTZS.js";
10
+ } from "./chunk-YBSBAJ3E.js";
11
+ import "./chunk-3A2DLR47.js";
12
+ import "./chunk-MNZKOZW7.js";
13
13
  export {
14
14
  cmdWorkspace,
15
15
  createWorkspaceHealthReport,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "Decantr CLI - scaffold, audit, inspect Project Health, and maintain Decantr projects from the terminal",
5
5
  "keywords": [
6
6
  "decantr",
@@ -48,11 +48,11 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "ajv": "^8.20.0",
51
+ "@decantr/core": "2.1.0",
52
+ "@decantr/essence-spec": "2.0.1",
51
53
  "@decantr/telemetry": "2.2.1",
52
54
  "@decantr/registry": "2.2.0",
53
- "@decantr/verifier": "2.5.0",
54
- "@decantr/core": "2.1.0",
55
- "@decantr/essence-spec": "2.0.1"
55
+ "@decantr/verifier": "2.5.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",