@decantr/cli 2.9.3 → 2.9.5

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
@@ -176,11 +176,11 @@ decantr verify --workspace --changed --since origin/main
176
176
  decantr export --to figma-tokens
177
177
  ```
178
178
 
179
- Use `--json` for machines and schema validation, `--markdown` for summaries, `--evidence` for the privacy-redacted Evidence Bundle, and `--prompt <finding-id>` when you want a scoped remediation prompt for an AI assistant. The prompt command prints instructions only; it does not modify source files. In monorepos, prompt commands preserve `--project <path>` so the finding resolves from the same app that produced it. `--browser` uses a project-local Playwright install and a supplied base URL to capture local route screenshots under `.decantr/evidence/screenshots/` and write `.decantr/evidence/visual-manifest.json`; missing Playwright becomes a visible setup finding/message, not a crash or silent skip. `--save-baseline` writes `.decantr/health-baseline.json`; `--since-baseline` writes `.decantr/health-baseline-diff.json` with changed files, route impact, finding deltas, screenshot hash drift, and contract drift. `--design-tokens <path>` compares a Tokens Studio/Figma token JSON export against Decantr CSS token names. `decantr ci --fail-on error` fails only when blocking errors exist; `decantr ci --fail-on warn` also fails on warnings.
179
+ Use `--json` for machines and schema validation, `--markdown` for summaries, `--evidence` for the privacy-redacted Evidence Bundle, and `--prompt <finding-id>` when you want a scoped remediation prompt for an AI assistant. The prompt command prints instructions only; it does not modify source files. In monorepos, prompt commands preserve `--project <path>`, include app-prefixed read targets such as `apps/web/DECANTR.md`, and use root-safe runtime commands such as `pnpm --dir apps/web build` so the finding resolves from the same app that produced it. `--browser` uses a project-local Playwright install and a supplied base URL to capture local route screenshots under `.decantr/evidence/screenshots/` and write `.decantr/evidence/visual-manifest.json`; missing Playwright becomes a visible setup finding/message, not a crash or silent skip. `--save-baseline` writes `.decantr/health-baseline.json`; `--since-baseline` writes `.decantr/health-baseline-diff.json` with changed files, route impact, finding deltas, screenshot hash drift, and contract drift. `--design-tokens <path>` compares a Tokens Studio/Figma token JSON export against Decantr CSS token names. `decantr ci --fail-on error` fails only when blocking errors exist; `decantr ci --fail-on warn` also fails on warnings.
180
180
 
181
181
  `decantr ci init` installs `.github/workflows/decantr-ci.yml` for GitHub Actions. The generated workflow installs dependencies at the workspace root, writes JSON/markdown CI artifacts, gates with `decantr ci`, appends the markdown report to the GitHub step summary, and uploads both files as artifacts. Use `--force` to replace an existing workflow or `--fail-on warn` for stricter repositories. In monorepos, add `--project <path>` from the repository root; dependency install stays at the root while CI evaluates the app contract and uploads app-scoped artifacts. Use `--workspace` to generate an aggregate gate. Use `--provider generic` for Jenkins, Please, Buildkite, GitLab, Azure DevOps, or internal deployment tools. Generated CI uses the pinned local package-manager command and does not depend on `@latest`. Project Health remediation prompts are also monorepo-aware, so missing-pack fixes use `apps/web/decantr.essence.json` and CI recommendations include `--project apps/web`.
182
182
 
183
- `decantr workspace` is the monorepo reliability namespace. Before attach, `workspace list` shows app candidates. After attach, it also discovers Decantr projects from `.decantr/workspace.json` or by finding `decantr.essence.json` files. Workspace health runs projects with deterministic ordering, concurrency, per-project timeout, failure isolation, and aggregate JSON, and can limit a run to changed projects:
183
+ `decantr workspace` is the monorepo reliability namespace. Before attach, `workspace list` shows app candidates. After attach, it also discovers Decantr projects from `.decantr/workspace.json` or by finding `decantr.essence.json` files, and it distinguishes "attach another app" from the empty-workspace first attach. Workspace health runs projects with deterministic ordering, concurrency, per-project timeout, failure isolation, and aggregate JSON, and can limit a run to changed projects:
184
184
 
185
185
  ```bash
186
186
  decantr workspace list
@@ -189,6 +189,8 @@ decantr workspace health --json --output .decantr/workspace-health.json
189
189
  decantr verify --workspace --changed --since origin/main
190
190
  ```
191
191
 
192
+ In observed Brownfield projects, common section shorthands are accepted for page additions when they resolve unambiguously. For example, `decantr add page app/settings --route /settings --project apps/web` resolves `app` to the single primary section, such as `observed-primary`, so docs and LLM prompts do not have to guess generated section IDs first.
193
+
192
194
  `decantr studio` starts a local-only dashboard powered by the same report. It uses Node built-ins only and serves `GET /`, `GET /api/health`, and `POST /api/refresh`.
193
195
 
194
196
  ```bash
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-VMNUJOEH.js";
2
+ import "./chunk-3KJ46XY7.js";
3
3
  import "./chunk-RXF7ZYGK.js";
4
- import "./chunk-ARR3EPS2.js";
5
- import "./chunk-XZFKK6V7.js";
6
- import "./chunk-34TZXWIF.js";
4
+ import "./chunk-VCUFZB45.js";
5
+ import "./chunk-FACL3NXU.js";
6
+ import "./chunk-WONPNSSI.js";
@@ -22,14 +22,14 @@ import {
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
24
  shouldFailWorkspaceHealth
25
- } from "./chunk-ARR3EPS2.js";
25
+ } from "./chunk-VCUFZB45.js";
26
26
  import {
27
27
  createProjectHealthReport,
28
28
  formatProjectHealthMarkdown,
29
29
  formatProjectHealthText,
30
30
  resolveWorkspaceInfo,
31
31
  shouldFailHealth
32
- } from "./chunk-XZFKK6V7.js";
32
+ } from "./chunk-FACL3NXU.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-34TZXWIF.js";
49
+ } from "./chunk-WONPNSSI.js";
50
50
 
51
51
  // src/index.ts
52
52
  import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync9, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "fs";
@@ -1743,6 +1743,7 @@ import { join as join6 } from "path";
1743
1743
  import { isV4 as isV42 } from "@decantr/essence-spec";
1744
1744
  var GREEN = "\x1B[32m";
1745
1745
  var RED = "\x1B[31m";
1746
+ var YELLOW = "\x1B[33m";
1746
1747
  var DIM = "\x1B[2m";
1747
1748
  var RESET = "\x1B[0m";
1748
1749
  function readV4Essence(projectRoot) {
@@ -1786,6 +1787,36 @@ function normalizeRoute(route) {
1786
1787
  if (!trimmed || trimmed === "/") return "/";
1787
1788
  return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
1788
1789
  }
1790
+ function resolveSectionForPage(sections, requestedSectionId) {
1791
+ const exact = sections.find((section) => section.id === requestedSectionId);
1792
+ if (exact) return { section: exact, resolvedFromAlias: false };
1793
+ const lower = requestedSectionId.toLowerCase();
1794
+ const roleByAlias = {
1795
+ app: "primary",
1796
+ main: "primary",
1797
+ primary: "primary",
1798
+ public: "public",
1799
+ marketing: "public",
1800
+ auth: "gateway",
1801
+ gateway: "gateway",
1802
+ auxiliary: "auxiliary"
1803
+ };
1804
+ const desiredRole = roleByAlias[lower];
1805
+ if (!desiredRole) return null;
1806
+ const roleMatches = sections.filter((section) => section.role === desiredRole);
1807
+ if (roleMatches.length === 1) return { section: roleMatches[0], resolvedFromAlias: true };
1808
+ if (roleMatches.length > 1) return null;
1809
+ const observedMatch = sections.find((section) => section.id === `observed-${desiredRole}`);
1810
+ return observedMatch ? { section: observedMatch, resolvedFromAlias: true } : null;
1811
+ }
1812
+ function printSectionNotFound(sectionId, sections, pageId) {
1813
+ console.error(`${RED}Section "${sectionId}" not found.${RESET}`);
1814
+ console.error(`${DIM}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET}`);
1815
+ if (pageId && sections.length > 0) {
1816
+ const primary = sections.find((section) => section.role === "primary") ?? sections[0];
1817
+ console.error(`${DIM}Try: decantr add page ${primary.id}/${pageId}${RESET}`);
1818
+ }
1819
+ }
1789
1820
  async function cmdAddSection(archetypeId, args, projectRoot = process.cwd()) {
1790
1821
  if (!archetypeId) {
1791
1822
  console.error(`${RED}Usage: decantr add section <archetypeId>${RESET}`);
@@ -1849,15 +1880,18 @@ async function cmdAddPage(path, args, projectRoot = process.cwd()) {
1849
1880
  if (!loaded) return;
1850
1881
  const { essence, essencePath } = loaded;
1851
1882
  const sections = essence.blueprint.sections;
1852
- const section = sections.find((s) => s.id === sectionId);
1853
- if (!section) {
1854
- console.error(`${RED}Section "${sectionId}" not found.${RESET}`);
1855
- console.error(`${DIM}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET}`);
1883
+ const resolved = resolveSectionForPage(sections, sectionId);
1884
+ if (!resolved) {
1885
+ printSectionNotFound(sectionId, sections, pageId);
1856
1886
  process.exitCode = 1;
1857
1887
  return;
1858
1888
  }
1889
+ const { section } = resolved;
1890
+ const resolvedSectionId = section.id;
1859
1891
  if (section.pages.find((p) => p.id === pageId)) {
1860
- console.error(`${RED}Page "${pageId}" already exists in section "${sectionId}".${RESET}`);
1892
+ console.error(
1893
+ `${RED}Page "${pageId}" already exists in section "${resolvedSectionId}".${RESET}`
1894
+ );
1861
1895
  process.exitCode = 1;
1862
1896
  return;
1863
1897
  }
@@ -1877,10 +1911,15 @@ async function cmdAddPage(path, args, projectRoot = process.cwd()) {
1877
1911
  route,
1878
1912
  layout: ["hero"]
1879
1913
  });
1880
- routes[route] = { section: sectionId, page: pageId };
1914
+ routes[route] = { section: resolvedSectionId, page: pageId };
1881
1915
  writeEssence(essencePath, essence);
1916
+ if (resolved.resolvedFromAlias) {
1917
+ console.log(
1918
+ `${YELLOW}Resolved section alias "${sectionId}" to "${resolvedSectionId}".${RESET}`
1919
+ );
1920
+ }
1882
1921
  console.log(
1883
- `${GREEN}Added page "${pageId}" to section "${sectionId}" at route "${route}".${RESET}`
1922
+ `${GREEN}Added page "${pageId}" to section "${resolvedSectionId}" at route "${route}".${RESET}`
1884
1923
  );
1885
1924
  const registryClient = new RegistryClient({
1886
1925
  cacheDir: join6(projectRoot, ".decantr", "cache")
@@ -2958,7 +2997,7 @@ var DIM2 = "\x1B[2m";
2958
2997
  var RESET2 = "\x1B[0m";
2959
2998
  var GREEN2 = "\x1B[32m";
2960
2999
  var CYAN = "\x1B[36m";
2961
- var YELLOW = "\x1B[33m";
3000
+ var YELLOW2 = "\x1B[33m";
2962
3001
  async function cmdAnalyze(projectRoot = process.cwd(), workspace) {
2963
3002
  const startedAt = Date.now();
2964
3003
  console.log(`
@@ -3126,7 +3165,7 @@ ${DIM2}Written to:${RESET2} ${outputPath}`);
3126
3165
  console.log(`${DIM2}Enrichment backlog:${RESET2} ${intelligenceArtifacts.backlogPath}`);
3127
3166
  console.log(
3128
3167
  `
3129
- ${YELLOW}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then run ${BOLD}${recommendedAttachCommand}${RESET2} to attach Decantr using the observed proposal.
3168
+ ${YELLOW2}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then run ${BOLD}${recommendedAttachCommand}${RESET2} to attach Decantr using the observed proposal.
3130
3169
  `
3131
3170
  );
3132
3171
  await sendAnalyzeCompletedTelemetry({
@@ -4257,7 +4296,7 @@ var BOLD3 = "\x1B[1m";
4257
4296
  var DIM4 = "\x1B[2m";
4258
4297
  var GREEN4 = "\x1B[32m";
4259
4298
  var RED3 = "\x1B[31m";
4260
- var YELLOW2 = "\x1B[33m";
4299
+ var YELLOW3 = "\x1B[33m";
4261
4300
  var CYAN2 = "\x1B[36m";
4262
4301
  var RESET4 = "\x1B[0m";
4263
4302
  function readJson2(path) {
@@ -4596,7 +4635,7 @@ function buildDoctorReport(root, args) {
4596
4635
  function colorForStatus(status) {
4597
4636
  if (status === "healthy") return GREEN4;
4598
4637
  if (status === "needs-setup" || status === "needs-migration") return RED3;
4599
- return YELLOW2;
4638
+ return YELLOW3;
4600
4639
  }
4601
4640
  function formatDoctorText(report) {
4602
4641
  const lines = [
@@ -4640,7 +4679,7 @@ function formatDoctorText(report) {
4640
4679
  lines.push(` ${GREEN4}No doctor findings.${RESET4}`);
4641
4680
  } else {
4642
4681
  for (const issue of report.issues) {
4643
- const color = issue.severity === "error" ? RED3 : issue.severity === "warn" ? YELLOW2 : CYAN2;
4682
+ const color = issue.severity === "error" ? RED3 : issue.severity === "warn" ? YELLOW3 : CYAN2;
4644
4683
  lines.push(
4645
4684
  ` ${color}[${issue.severity.toUpperCase()}]${RESET4} ${issue.category}: ${issue.message}`
4646
4685
  );
@@ -4682,6 +4721,16 @@ var GREEN5 = "\x1B[32m";
4682
4721
  var RED4 = "\x1B[31m";
4683
4722
  var DIM5 = "\x1B[2m";
4684
4723
  var RESET5 = "\x1B[0m";
4724
+ function readAdoptionMode(projectRoot) {
4725
+ const projectJsonPath = join19(projectRoot, ".decantr", "project.json");
4726
+ if (!existsSync17(projectJsonPath)) return null;
4727
+ try {
4728
+ const parsed = JSON.parse(readFileSync14(projectJsonPath, "utf-8"));
4729
+ return typeof parsed.initialized?.adoptionMode === "string" ? parsed.initialized.adoptionMode : null;
4730
+ } catch {
4731
+ return null;
4732
+ }
4733
+ }
4685
4734
  function resolveOutputPath(projectRoot, output, fallback) {
4686
4735
  if (!output) return fallback;
4687
4736
  return isAbsolute(output) ? output : join19(projectRoot, output);
@@ -4853,9 +4902,9 @@ async function cmdExport(target, projectRoot, options = {}) {
4853
4902
  return;
4854
4903
  }
4855
4904
  if (!existsSync17(tokensPath)) {
4856
- console.error(
4857
- `${RED4}No src/styles/tokens.css found. Run \`decantr refresh\` to generate tokens.${RESET5}`
4858
- );
4905
+ const adoptionMode = readAdoptionMode(projectRoot);
4906
+ 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.";
4907
+ console.error(`${RED4}${message}${RESET5}`);
4859
4908
  process.exitCode = 1;
4860
4909
  return;
4861
4910
  }
@@ -4936,7 +4985,7 @@ var DIM6 = "\x1B[2m";
4936
4985
  var RESET6 = "\x1B[0m";
4937
4986
  var GREEN6 = "\x1B[32m";
4938
4987
  var CYAN3 = "\x1B[36m";
4939
- var YELLOW3 = "\x1B[33m";
4988
+ var YELLOW4 = "\x1B[33m";
4940
4989
  var MAGENTA = "\x1B[35m";
4941
4990
  function success(text) {
4942
4991
  return `${GREEN6}${text}${RESET6}`;
@@ -5157,7 +5206,7 @@ async function cmdMagic(prompt, projectRoot, options) {
5157
5206
  const essencePath = join20(projectRoot, "decantr.essence.json");
5158
5207
  if (existsSync18(essencePath)) {
5159
5208
  const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5160
- console.log(`${YELLOW3} Decantr is already attached to this project.${RESET6}`);
5209
+ console.log(`${YELLOW4} Decantr is already attached to this project.${RESET6}`);
5161
5210
  console.log(
5162
5211
  dim(" decantr magic is greenfield-first; use task-time context for existing apps.")
5163
5212
  );
@@ -5170,7 +5219,7 @@ async function cmdMagic(prompt, projectRoot, options) {
5170
5219
  }
5171
5220
  const detected = detectProject(projectRoot);
5172
5221
  if (hasExistingProjectFootprint(detected)) {
5173
- console.log(`${YELLOW3} Existing project detected.${RESET6}`);
5222
+ console.log(`${YELLOW4} Existing project detected.${RESET6}`);
5174
5223
  console.log(
5175
5224
  dim(
5176
5225
  " decantr magic stays greenfield-first and will not silently bootstrap over an existing app."
@@ -5480,7 +5529,7 @@ ${GREEN6}${BOLD4}Quality summary:${RESET6}`);
5480
5529
  );
5481
5530
  console.log(` CSS: tokens.css + treatments.css + global.css`);
5482
5531
  console.log(
5483
- ` @layer cascade: ${hasLayers ? GREEN6 + "yes" + RESET6 : YELLOW3 + "missing" + RESET6}`
5532
+ ` @layer cascade: ${hasLayers ? GREEN6 + "yes" + RESET6 : YELLOW4 + "missing" + RESET6}`
5484
5533
  );
5485
5534
  console.log("");
5486
5535
  console.log(`${BOLD4} Ready!${RESET6} Next steps:`);
@@ -5509,7 +5558,7 @@ import {
5509
5558
  } from "@decantr/essence-spec";
5510
5559
  var GREEN7 = "\x1B[32m";
5511
5560
  var RED5 = "\x1B[31m";
5512
- var YELLOW4 = "\x1B[33m";
5561
+ var YELLOW5 = "\x1B[33m";
5513
5562
  var RESET7 = "\x1B[0m";
5514
5563
  var DIM7 = "\x1B[2m";
5515
5564
  function migrateEssenceFile(essencePath) {
@@ -5609,7 +5658,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5609
5658
  console.log(`${GREEN7}Derived context and execution packs refreshed.${RESET7}`);
5610
5659
  }
5611
5660
  console.log("");
5612
- console.log(`${YELLOW4}Review the migrated file and run \`decantr check\` to verify.${RESET7}`);
5661
+ console.log(`${YELLOW5}Review the migrated file and run \`decantr check\` to verify.${RESET7}`);
5613
5662
  }
5614
5663
 
5615
5664
  // src/commands/new-project.ts
@@ -5676,7 +5725,7 @@ var RESET8 = "\x1B[0m";
5676
5725
  var RED6 = "\x1B[31m";
5677
5726
  var GREEN8 = "\x1B[32m";
5678
5727
  var CYAN4 = "\x1B[36m";
5679
- var YELLOW5 = "\x1B[33m";
5728
+ var YELLOW6 = "\x1B[33m";
5680
5729
  function heading(text) {
5681
5730
  return `
5682
5731
  ${BOLD5}${text}${RESET8}
@@ -5826,7 +5875,7 @@ async function cmdNewProject(projectName, options) {
5826
5875
  );
5827
5876
  } else {
5828
5877
  console.log(
5829
- `${YELLOW5} No greenfield bootstrap adapter is available yet for target "${bootstrapTarget.target}" (${bootstrapTarget.packAdapter}).${RESET8}`
5878
+ `${YELLOW6} No greenfield bootstrap adapter is available yet for target "${bootstrapTarget.target}" (${bootstrapTarget.packAdapter}).${RESET8}`
5830
5879
  );
5831
5880
  console.log(
5832
5881
  dim2(
@@ -5842,7 +5891,7 @@ async function cmdNewProject(projectName, options) {
5842
5891
  } catch {
5843
5892
  console.log(
5844
5893
  `
5845
- ${YELLOW5}Dependency install failed. Run \`${packageManager} install\` manually.${RESET8}`
5894
+ ${YELLOW6}Dependency install failed. Run \`${packageManager} install\` manually.${RESET8}`
5846
5895
  );
5847
5896
  }
5848
5897
  }
@@ -5854,7 +5903,7 @@ ${YELLOW5}Dependency install failed. Run \`${packageManager} install\` manually.
5854
5903
  console.log(dim2(` Seeded offline registry content from ${seeded.strategy}.`));
5855
5904
  } else if (requiresOfflineContent) {
5856
5905
  console.log(
5857
- `${YELLOW5} Offline blueprint/archetype resolution requires local registry content.${RESET8}`
5906
+ `${YELLOW6} Offline blueprint/archetype resolution requires local registry content.${RESET8}`
5858
5907
  );
5859
5908
  console.log(
5860
5909
  dim2(
@@ -5884,7 +5933,7 @@ ${YELLOW5}Dependency install failed. Run \`${packageManager} install\` manually.
5884
5933
  } catch {
5885
5934
  console.log(
5886
5935
  `
5887
- ${YELLOW5}Decantr init encountered issues. Run \`decantr init\` manually inside ${projectName}/.${RESET8}`
5936
+ ${YELLOW6}Decantr init encountered issues. Run \`decantr init\` manually inside ${projectName}/.${RESET8}`
5888
5937
  );
5889
5938
  }
5890
5939
  console.log(success2(`
@@ -6227,7 +6276,7 @@ var GREEN10 = "\x1B[32m";
6227
6276
  var RED8 = "\x1B[31m";
6228
6277
  var DIM10 = "\x1B[2m";
6229
6278
  var CYAN5 = "\x1B[36m";
6230
- var YELLOW6 = "\x1B[33m";
6279
+ var YELLOW7 = "\x1B[33m";
6231
6280
  var RESET10 = "\x1B[0m";
6232
6281
  var ALL_CONTENT_TYPES = [...API_CONTENT_TYPES];
6233
6282
  async function cmdRegistryMirror(projectRoot, options = {}) {
@@ -6291,7 +6340,7 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6291
6340
  const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
6292
6341
  console.log("");
6293
6342
  if (failed.length > 0) {
6294
- console.log(`${YELLOW6}Mirrored ${totalItems} items (${failed.length} type(s) failed)${RESET10}`);
6343
+ console.log(`${YELLOW7}Mirrored ${totalItems} items (${failed.length} type(s) failed)${RESET10}`);
6295
6344
  } else {
6296
6345
  console.log(
6297
6346
  `${GREEN10}Mirrored ${totalItems} items across ${Object.keys(counts).length} types${RESET10}`
@@ -6479,7 +6528,7 @@ import { existsSync as existsSync26, readFileSync as readFileSync19, writeFileSy
6479
6528
  import { join as join28 } from "path";
6480
6529
  var GREEN12 = "\x1B[32m";
6481
6530
  var RED10 = "\x1B[31m";
6482
- var YELLOW7 = "\x1B[33m";
6531
+ var YELLOW8 = "\x1B[33m";
6483
6532
  var RESET12 = "\x1B[0m";
6484
6533
  var DIM12 = "\x1B[2m";
6485
6534
  var BOLD6 = "\x1B[1m";
@@ -6520,7 +6569,7 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6520
6569
  `);
6521
6570
  for (let i = 0; i < unresolved.length; i++) {
6522
6571
  const entry = unresolved[i];
6523
- const severityColor = entry.severity === "error" ? RED10 : YELLOW7;
6572
+ const severityColor = entry.severity === "error" ? RED10 : YELLOW8;
6524
6573
  const icon = entry.severity === "error" ? "x" : "!";
6525
6574
  console.log(
6526
6575
  ` ${severityColor}${icon}${RESET12} ${BOLD6}#${i + 1}${RESET12} [${entry.rule}] ${entry.message}`
@@ -6804,7 +6853,7 @@ import { join as join29 } from "path";
6804
6853
  import { isV4 as isV48 } from "@decantr/essence-spec";
6805
6854
  var GREEN14 = "\x1B[32m";
6806
6855
  var RED11 = "\x1B[31m";
6807
- var YELLOW8 = "\x1B[33m";
6856
+ var YELLOW9 = "\x1B[33m";
6808
6857
  var DIM14 = "\x1B[2m";
6809
6858
  var RESET14 = "\x1B[0m";
6810
6859
  var VALID_THEME_SHAPES = ["sharp", "rounded", "pill"];
@@ -6899,7 +6948,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6899
6948
  console.log(
6900
6949
  `${GREEN14}Derived files refreshed (tokens.css, treatments.css, all contexts).${RESET14}`
6901
6950
  );
6902
- console.log(`${YELLOW8}Guard will flag code using old tokens. Run \`decantr check\`.${RESET14}`);
6951
+ console.log(`${YELLOW9}Guard will flag code using old tokens. Run \`decantr check\`.${RESET14}`);
6903
6952
  }
6904
6953
 
6905
6954
  // src/prompts.ts
@@ -6908,7 +6957,7 @@ var BOLD8 = "\x1B[1m";
6908
6957
  var DIM15 = "\x1B[2m";
6909
6958
  var RESET15 = "\x1B[0m";
6910
6959
  var GREEN15 = "\x1B[32m";
6911
- var YELLOW9 = "\x1B[33m";
6960
+ var YELLOW10 = "\x1B[33m";
6912
6961
  var CYAN8 = "\x1B[36m";
6913
6962
  function ask(question, defaultValue) {
6914
6963
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -6948,7 +6997,7 @@ async function confirm(question, defaultYes = true) {
6948
6997
  }
6949
6998
  function warn(message) {
6950
6999
  console.log(`
6951
- ${YELLOW9} Warning: ${message}${RESET15}`);
7000
+ ${YELLOW10} Warning: ${message}${RESET15}`);
6952
7001
  }
6953
7002
  function showDetection(detected) {
6954
7003
  console.log(`
@@ -6967,7 +7016,7 @@ ${CYAN8}Detected project configuration:${RESET15}`);
6967
7016
  console.log(` Tailwind CSS: ${GREEN15}yes${RESET15}`);
6968
7017
  }
6969
7018
  if (detected.existingEssence) {
6970
- console.log(` Existing essence: ${YELLOW9}yes${RESET15}`);
7019
+ console.log(` Existing essence: ${YELLOW10}yes${RESET15}`);
6971
7020
  }
6972
7021
  }
6973
7022
  async function runInteractivePrompts(detected, archetypes, blueprints, themes, workflowSeed) {
@@ -7369,7 +7418,7 @@ var RESET16 = "\x1B[0m";
7369
7418
  var RED12 = "\x1B[31m";
7370
7419
  var GREEN16 = "\x1B[32m";
7371
7420
  var CYAN9 = "\x1B[36m";
7372
- var YELLOW10 = "\x1B[33m";
7421
+ var YELLOW11 = "\x1B[33m";
7373
7422
  function heading2(text) {
7374
7423
  return `
7375
7424
  ${BOLD9}${text}${RESET16}
@@ -8412,7 +8461,7 @@ function printBlueprintPortfolioNotice(blueprint) {
8412
8461
  if (!portfolio) return;
8413
8462
  if (portfolio.visibility === "hidden" || portfolio.maturity === "fold-candidate") {
8414
8463
  console.log(
8415
- `${YELLOW10} Warning:${RESET16} blueprint "${blueprint.id}" is folded out of public browsing.`
8464
+ `${YELLOW11} Warning:${RESET16} blueprint "${blueprint.id}" is folded out of public browsing.`
8416
8465
  );
8417
8466
  if (portfolio.recommended_alternative) {
8418
8467
  console.log(
@@ -8425,7 +8474,7 @@ function printBlueprintPortfolioNotice(blueprint) {
8425
8474
  }
8426
8475
  if (portfolio.visibility === "labs") {
8427
8476
  console.log(
8428
- `${YELLOW10} Note:${RESET16} blueprint "${blueprint.id}" is a Labs blueprint; direct scaffolding is supported, but it is not a default recommendation yet.`
8477
+ `${YELLOW11} Note:${RESET16} blueprint "${blueprint.id}" is a Labs blueprint; direct scaffolding is supported, but it is not a default recommendation yet.`
8429
8478
  );
8430
8479
  }
8431
8480
  }
@@ -8714,7 +8763,7 @@ async function cmdValidate(path) {
8714
8763
  console.log(heading2("Guard violations:"));
8715
8764
  for (const v of violations) {
8716
8765
  const vr = v;
8717
- console.log(` ${YELLOW10}[${vr.rule}]${RESET16} ${vr.message}`);
8766
+ console.log(` ${YELLOW11}[${vr.rule}]${RESET16} ${vr.message}`);
8718
8767
  if (vr.suggestion) {
8719
8768
  console.log(` ${DIM16}Suggestion: ${vr.suggestion}${RESET16}`);
8720
8769
  }
@@ -9048,7 +9097,7 @@ async function cmdInit(args) {
9048
9097
  console.log(dim3(" Found .decantr/init-seed.json brownfield guidance."));
9049
9098
  }
9050
9099
  if (detected.existingEssence && !args.existing) {
9051
- console.log(`${YELLOW10}Warning: decantr.essence.json already exists.${RESET16}`);
9100
+ console.log(`${YELLOW11}Warning: decantr.essence.json already exists.${RESET16}`);
9052
9101
  const overwrite = await confirm("Overwrite existing configuration?", false);
9053
9102
  if (!overwrite) {
9054
9103
  console.log(dim3("Cancelled."));
@@ -9151,7 +9200,7 @@ async function cmdInit(args) {
9151
9200
  } else if (shouldUseRegistry && !apiAvailable) {
9152
9201
  if (!args.blueprint) {
9153
9202
  console.log(`
9154
- ${YELLOW10}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9203
+ ${YELLOW11}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9155
9204
  console.log(
9156
9205
  dim3("Run `decantr sync` or `decantr upgrade` when online to pull full registry content.\n")
9157
9206
  );
@@ -9200,7 +9249,7 @@ ${YELLOW10}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9200
9249
  return;
9201
9250
  }
9202
9251
  console.log(`
9203
- ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9252
+ ${YELLOW11}You're offline. Scaffolding Decantr default.${RESET16}`);
9204
9253
  console.log(dim3("Run `decantr upgrade` when online, or visit decantr.ai/registry\n"));
9205
9254
  selectedBlueprint = "default";
9206
9255
  } else if (shouldUseRegistry) {
@@ -9382,7 +9431,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9382
9431
  return;
9383
9432
  }
9384
9433
  console.log(
9385
- `${YELLOW10} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET16}`
9434
+ `${YELLOW11} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET16}`
9386
9435
  );
9387
9436
  }
9388
9437
  } else if (shouldUseRegistry && options.archetype) {
@@ -9397,7 +9446,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9397
9446
  return;
9398
9447
  }
9399
9448
  console.log(
9400
- `${YELLOW10} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET16}`
9449
+ `${YELLOW11} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET16}`
9401
9450
  );
9402
9451
  }
9403
9452
  }
@@ -9414,7 +9463,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9414
9463
  return;
9415
9464
  }
9416
9465
  console.log(
9417
- `${YELLOW10} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET16}`
9466
+ `${YELLOW11} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET16}`
9418
9467
  );
9419
9468
  }
9420
9469
  }
@@ -9619,7 +9668,7 @@ async function cmdStatus(projectRoot = process.cwd()) {
9619
9668
  ` Guard: ${v4.meta.guard.mode} (DNA: ${v4.meta.guard.dna_enforcement}, Blueprint: ${v4.meta.guard.blueprint_enforcement})`
9620
9669
  );
9621
9670
  } else {
9622
- console.log(` ${YELLOW10}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9671
+ console.log(` ${YELLOW11}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9623
9672
  }
9624
9673
  } catch (e) {
9625
9674
  console.log(` ${RED12}Error reading essence: ${e.message}${RESET16}`);
@@ -9632,15 +9681,15 @@ async function cmdStatus(projectRoot = process.cwd()) {
9632
9681
  const syncStatus = projectJson.sync?.status || "unknown";
9633
9682
  const lastSync = projectJson.sync?.lastSync || "never";
9634
9683
  const source = projectJson.sync?.registrySource || "unknown";
9635
- const statusColor = syncStatus === "synced" ? GREEN16 : YELLOW10;
9684
+ const statusColor = syncStatus === "synced" ? GREEN16 : YELLOW11;
9636
9685
  console.log(` Status: ${statusColor}${syncStatus}${RESET16}`);
9637
9686
  console.log(` Last sync: ${dim3(lastSync)}`);
9638
9687
  console.log(` Source: ${dim3(source)}`);
9639
9688
  } catch {
9640
- console.log(` ${YELLOW10}Could not read project.json${RESET16}`);
9689
+ console.log(` ${YELLOW11}Could not read project.json${RESET16}`);
9641
9690
  }
9642
9691
  } else {
9643
- console.log(` ${YELLOW10}No .decantr/project.json found${RESET16}`);
9692
+ console.log(` ${YELLOW11}No .decantr/project.json found${RESET16}`);
9644
9693
  console.log(dim3(' Run "decantr init" to create project files.'));
9645
9694
  }
9646
9695
  }
@@ -9653,12 +9702,12 @@ async function cmdSync() {
9653
9702
  console.log(success3("Sync completed successfully."));
9654
9703
  console.log(` Synced: ${result.synced.join(", ")}`);
9655
9704
  if (result.failed.length > 0) {
9656
- console.log(` ${YELLOW10}Failed: ${result.failed.join(", ")}${RESET16}`);
9705
+ console.log(` ${YELLOW11}Failed: ${result.failed.join(", ")}${RESET16}`);
9657
9706
  }
9658
9707
  } else {
9659
- console.log(`${YELLOW10}Could not sync: API unavailable${RESET16}`);
9708
+ console.log(`${YELLOW11}Could not sync: API unavailable${RESET16}`);
9660
9709
  if (result.failed.length > 0) {
9661
- console.log(` ${YELLOW10}Failed: ${result.failed.join(", ")}${RESET16}`);
9710
+ console.log(` ${YELLOW11}Failed: ${result.failed.join(", ")}${RESET16}`);
9662
9711
  }
9663
9712
  }
9664
9713
  }
@@ -9668,7 +9717,7 @@ function printVerificationFindings(findings) {
9668
9717
  return;
9669
9718
  }
9670
9719
  for (const finding of findings) {
9671
- const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9720
+ const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW11 : CYAN9;
9672
9721
  console.log(
9673
9722
  ` ${color}[${finding.severity.toUpperCase()}]${RESET16} ${finding.category}: ${finding.message}`
9674
9723
  );
@@ -10309,7 +10358,7 @@ async function cmdAdoptWorkflow(args) {
10309
10358
  )
10310
10359
  );
10311
10360
  } catch (e) {
10312
- console.log(`${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`);
10361
+ console.log(`${YELLOW11}Pack hydration skipped:${RESET16} ${e.message}`);
10313
10362
  console.log(
10314
10363
  dim3(
10315
10364
  `Run ${compilePacksCommandForProject(projectArg)} after adoption if you want hosted page/review packs.`
@@ -10320,7 +10369,7 @@ async function cmdAdoptWorkflow(args) {
10320
10369
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
10321
10370
  }
10322
10371
  if (runVerify) {
10323
- const { cmdHealth } = await import("./health-MB63O56B.js");
10372
+ const { cmdHealth } = await import("./health-R7AV5G4V.js");
10324
10373
  await cmdHealth(projectRoot, {
10325
10374
  browser: runBrowser,
10326
10375
  browserBaseUrl: baseUrl,
@@ -10391,7 +10440,7 @@ async function cmdVerifyWorkflow(args) {
10391
10440
  return;
10392
10441
  }
10393
10442
  if (workspaceMode) {
10394
- const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
10443
+ const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
10395
10444
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
10396
10445
  return;
10397
10446
  }
@@ -10424,7 +10473,7 @@ async function cmdVerifyWorkflow(args) {
10424
10473
  }
10425
10474
  let guardExitCode;
10426
10475
  if (brownfield) {
10427
- const { cmdHeal, collectCheckIssues } = await import("./heal-2BDT7TR5.js");
10476
+ const { cmdHeal, collectCheckIssues } = await import("./heal-ZQHEHBUJ.js");
10428
10477
  if (quietOutput) {
10429
10478
  const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
10430
10479
  guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
@@ -10434,7 +10483,7 @@ async function cmdVerifyWorkflow(args) {
10434
10483
  process.exitCode = void 0;
10435
10484
  }
10436
10485
  }
10437
- const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
10486
+ const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
10438
10487
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10439
10488
  if (localPatterns) {
10440
10489
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10442,7 +10491,7 @@ async function cmdVerifyWorkflow(args) {
10442
10491
  if (!quietOutput) {
10443
10492
  console.log("");
10444
10493
  console.log(
10445
- `${YELLOW10}Local pattern pack missing.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))}, review the proposal, then run ${cyan3(withProject("decantr codify --accept", projectArg))}.`
10494
+ `${YELLOW11}Local pattern pack missing.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))}, review the proposal, then run ${cyan3(withProject("decantr codify --accept", projectArg))}.`
10446
10495
  );
10447
10496
  }
10448
10497
  process.exitCode = process.exitCode || 1;
@@ -10458,11 +10507,11 @@ async function cmdVerifyWorkflow(args) {
10458
10507
  console.log(`${GREEN16}Local rule manifest found:${RESET16} ${validation.rulesPath}`);
10459
10508
  } else {
10460
10509
  console.log(
10461
- `${YELLOW10}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
10510
+ `${YELLOW11}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
10462
10511
  );
10463
10512
  }
10464
10513
  for (const warning of validation.warnings.slice(0, 8)) {
10465
- console.log(`${YELLOW10}warn${RESET16} ${warning}`);
10514
+ console.log(`${YELLOW11}warn${RESET16} ${warning}`);
10466
10515
  }
10467
10516
  if (validation.findings.length > 0) {
10468
10517
  console.log("");
@@ -10615,7 +10664,7 @@ async function cmdTaskWorkflow(args) {
10615
10664
  console.log("");
10616
10665
  console.log(`${BOLD9}Project-owned local law:${RESET16}`);
10617
10666
  console.log(
10618
- ` ${YELLOW10}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
10667
+ ` ${YELLOW11}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
10619
10668
  );
10620
10669
  }
10621
10670
  if (context.changedFiles.length > 0) {
@@ -11414,10 +11463,10 @@ async function main() {
11414
11463
  case "heal": {
11415
11464
  if (command === "heal") {
11416
11465
  console.log(
11417
- `${YELLOW10}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11466
+ `${YELLOW11}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11418
11467
  );
11419
11468
  }
11420
- const { cmdHeal } = await import("./heal-2BDT7TR5.js");
11469
+ const { cmdHeal } = await import("./heal-ZQHEHBUJ.js");
11421
11470
  const { flags } = parseLooseArgs(args);
11422
11471
  const workspaceInfo = resolveWorkflowProject(flags, "check");
11423
11472
  if (!workspaceInfo) break;
@@ -11442,7 +11491,7 @@ async function main() {
11442
11491
  const { flags } = parseLooseArgs(args);
11443
11492
  const workspaceInfo = resolveWorkflowProject(flags, "health");
11444
11493
  if (!workspaceInfo) break;
11445
- const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
11494
+ const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
11446
11495
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
11447
11496
  } catch (e) {
11448
11497
  console.error(error2(e.message));
@@ -11470,7 +11519,7 @@ async function main() {
11470
11519
  cmdStudioHelp();
11471
11520
  break;
11472
11521
  }
11473
- const { cmdStudio, parseStudioArgs } = await import("./studio-6QGXJBVH.js");
11522
+ const { cmdStudio, parseStudioArgs } = await import("./studio-2734P63C.js");
11474
11523
  await cmdStudio(process.cwd(), parseStudioArgs(args));
11475
11524
  } catch (e) {
11476
11525
  console.error(error2(e.message));
@@ -11484,7 +11533,7 @@ async function main() {
11484
11533
  cmdWorkspaceHelp();
11485
11534
  break;
11486
11535
  }
11487
- const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
11536
+ const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
11488
11537
  await cmdWorkspace(process.cwd(), args);
11489
11538
  } catch (e) {
11490
11539
  console.error(error2(e.message));
@@ -3,7 +3,7 @@ import {
3
3
  sendProjectHealthCiFailedTelemetry,
4
4
  sendProjectHealthPromptTelemetry,
5
5
  sendProjectHealthReportTelemetry
6
- } from "./chunk-34TZXWIF.js";
6
+ } from "./chunk-WONPNSSI.js";
7
7
 
8
8
  // src/commands/health.ts
9
9
  import { execFileSync } from "child_process";
@@ -383,6 +383,47 @@ function commandsForFinding(source) {
383
383
  return ["decantr audit", "decantr health"];
384
384
  }
385
385
  }
386
+ function detectPackageManager(root) {
387
+ const pkg = readJsonFile(join2(root, "package.json"));
388
+ const declared = pkg?.packageManager?.split("@")[0];
389
+ if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
390
+ return declared;
391
+ }
392
+ if (existsSync2(join2(root, "pnpm-lock.yaml"))) return "pnpm";
393
+ if (existsSync2(join2(root, "package-lock.json"))) return "npm";
394
+ if (existsSync2(join2(root, "yarn.lock"))) return "yarn";
395
+ if (existsSync2(join2(root, "bun.lock")) || existsSync2(join2(root, "bun.lockb"))) return "bun";
396
+ return "unknown";
397
+ }
398
+ function buildCommandForProject(workspaceRoot, projectPath) {
399
+ const packageManager = detectPackageManager(workspaceRoot);
400
+ if (projectPath) {
401
+ switch (packageManager) {
402
+ case "pnpm":
403
+ return `pnpm --dir ${projectPath} build`;
404
+ case "yarn":
405
+ return `yarn --cwd ${projectPath} build`;
406
+ case "bun":
407
+ return `bun --cwd ${projectPath} run build`;
408
+ case "npm":
409
+ return `npm --prefix ${projectPath} run build`;
410
+ default:
411
+ return `cd ${projectPath} && npm run build`;
412
+ }
413
+ }
414
+ switch (packageManager) {
415
+ case "pnpm":
416
+ return "pnpm build";
417
+ case "yarn":
418
+ return "yarn build";
419
+ case "bun":
420
+ return "bun run build";
421
+ case "npm":
422
+ return "npm run build";
423
+ default:
424
+ return "npm run build";
425
+ }
426
+ }
386
427
  function commandContextForProject(projectRoot) {
387
428
  const workspaceInfo = resolveWorkspaceInfo(projectRoot);
388
429
  const relativeProjectPath = relative(workspaceInfo.workspaceRoot, projectRoot).replace(
@@ -394,6 +435,7 @@ function commandContextForProject(projectRoot) {
394
435
  const essencePath = projectPath ? `${projectPath}/decantr.essence.json` : "decantr.essence.json";
395
436
  return {
396
437
  projectPath,
438
+ buildCommand: buildCommandForProject(workspaceInfo.workspaceRoot, projectPath),
397
439
  compilePacksCommand: `decantr registry compile-packs ${essencePath} --write-context`,
398
440
  verifyCommand: `decantr verify${projectFlag}`,
399
441
  ciCommand: `decantr ci${projectFlag} --fail-on error`,
@@ -401,6 +443,7 @@ function commandContextForProject(projectRoot) {
401
443
  };
402
444
  }
403
445
  function rewriteHealthCommand(command, context) {
446
+ if (command === "npm run build") return context.buildCommand;
404
447
  let rewritten = command.replace(
405
448
  /decantr registry compile-packs decantr\.essence\.json --write-context/g,
406
449
  context.compilePacksCommand
@@ -461,17 +504,25 @@ function scopeHealthFindingsToProject(projectRoot, findings) {
461
504
  message: finding.message,
462
505
  evidence: finding.evidence,
463
506
  suggestedFix,
464
- commands
507
+ commands,
508
+ projectPath: context.projectPath
465
509
  })
466
510
  }
467
511
  };
468
512
  });
469
513
  }
470
514
  function buildRemediationPrompt(input) {
515
+ const prefix = input.projectPath ? `${input.projectPath}/` : "";
516
+ const readTargets = [
517
+ `${prefix}DECANTR.md`,
518
+ `${prefix}decantr.essence.json`,
519
+ `${prefix}.decantr/context/scaffold-pack.md`,
520
+ `${prefix}.decantr/context/scaffold.md`
521
+ ];
471
522
  return [
472
523
  "You are fixing one Decantr Project Health finding in this local workspace.",
473
524
  "",
474
- "Read `DECANTR.md`, `decantr.essence.json`, and `.decantr/context/scaffold-pack.md` if they exist. For route or page work, read the matching page/section packs before editing.",
525
+ `Read project-scoped Decantr files if they exist: ${readTargets.map((target) => `\`${target}\``).join(", ")}. For route or page work, read the matching page/section packs before editing.`,
475
526
  "",
476
527
  `Finding: ${input.id}`,
477
528
  `Source: ${input.source}`,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createProjectHealthReport,
3
3
  listWorkspaceAppCandidates
4
- } from "./chunk-XZFKK6V7.js";
4
+ } from "./chunk-FACL3NXU.js";
5
5
 
6
6
  // src/commands/workspace.ts
7
7
  import { execFileSync } from "child_process";
@@ -322,7 +322,7 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
322
322
  }
323
323
  if (unattachedCandidates.length > 0) {
324
324
  console.log("");
325
- console.log("Start by attaching one app:");
325
+ console.log(projects.length > 0 ? "Attach another app:" : "Start by attaching one app:");
326
326
  console.log(` ${unattachedCandidates[0].suggestedAdoptCommand}`);
327
327
  }
328
328
  return;
@@ -1323,6 +1323,22 @@ var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
1323
1323
  ".cache"
1324
1324
  ]);
1325
1325
  var MAX_FILE_SIZE = 1024 * 1024;
1326
+ function isNonUiInteractionSource(relativePath) {
1327
+ const normalized2 = relativePath.replace(/\\/g, "/");
1328
+ if (/\.d\.ts$/i.test(normalized2)) return true;
1329
+ if (/(?:^|\/)(?:__tests__|__mocks__|tests?|specs?|fixtures?|mocks?|stories?)(?:\/|$)/i.test(
1330
+ normalized2
1331
+ )) {
1332
+ return true;
1333
+ }
1334
+ if (/\.(?:test|spec|stories?|story|fixture|mock)\.(?:[cm]?[jt]sx?|mdx|html)$/i.test(normalized2)) {
1335
+ return true;
1336
+ }
1337
+ if (/^(?:src\/)?app\/api\//i.test(normalized2)) return true;
1338
+ if (/^(?:src\/)?pages\/api\//i.test(normalized2)) return true;
1339
+ if (/(?:^|\/)route\.[cm]?[jt]s$/i.test(normalized2)) return true;
1340
+ return false;
1341
+ }
1326
1342
  function walkSourceTree(rootDir) {
1327
1343
  const sources = /* @__PURE__ */ new Map();
1328
1344
  function walk2(dir) {
@@ -1341,12 +1357,14 @@ function walkSourceTree(rootDir) {
1341
1357
  } catch {
1342
1358
  continue;
1343
1359
  }
1360
+ const relativePath = relative3(rootDir, fullPath) || entry;
1344
1361
  if (s.isDirectory()) {
1345
1362
  walk2(fullPath);
1346
1363
  } else if (s.isFile() && SCAN_EXTENSIONS.has(extname2(entry))) {
1347
1364
  if (s.size > MAX_FILE_SIZE) continue;
1365
+ if (isNonUiInteractionSource(relativePath)) continue;
1348
1366
  try {
1349
- sources.set(relative3(rootDir, fullPath) || entry, readFileSync8(fullPath, "utf8"));
1367
+ sources.set(relativePath, readFileSync8(fullPath, "utf8"));
1350
1368
  } catch {
1351
1369
  }
1352
1370
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cmdHeal,
3
3
  collectCheckIssues
4
- } from "./chunk-34TZXWIF.js";
4
+ } from "./chunk-WONPNSSI.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-XZFKK6V7.js";
14
- import "./chunk-34TZXWIF.js";
13
+ } from "./chunk-FACL3NXU.js";
14
+ import "./chunk-WONPNSSI.js";
15
15
  export {
16
16
  cmdHealth,
17
17
  collectDesignTokenEvidence,
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./chunk-VMNUJOEH.js";
1
+ import "./chunk-3KJ46XY7.js";
2
2
  import "./chunk-RXF7ZYGK.js";
3
- import "./chunk-ARR3EPS2.js";
4
- import "./chunk-XZFKK6V7.js";
5
- import "./chunk-34TZXWIF.js";
3
+ import "./chunk-VCUFZB45.js";
4
+ import "./chunk-FACL3NXU.js";
5
+ import "./chunk-WONPNSSI.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createWorkspaceHealthReport
3
- } from "./chunk-ARR3EPS2.js";
3
+ } from "./chunk-VCUFZB45.js";
4
4
  import {
5
5
  createProjectHealthReport
6
- } from "./chunk-XZFKK6V7.js";
6
+ } from "./chunk-FACL3NXU.js";
7
7
  import {
8
8
  sendStudioHealthRefreshedTelemetry,
9
9
  sendStudioStartedTelemetry
10
- } from "./chunk-34TZXWIF.js";
10
+ } from "./chunk-WONPNSSI.js";
11
11
 
12
12
  // src/commands/studio.ts
13
13
  import { readFileSync } from "fs";
@@ -7,9 +7,9 @@ import {
7
7
  listWorkspaceProjects,
8
8
  parseWorkspaceArgs,
9
9
  shouldFailWorkspaceHealth
10
- } from "./chunk-ARR3EPS2.js";
11
- import "./chunk-XZFKK6V7.js";
12
- import "./chunk-34TZXWIF.js";
10
+ } from "./chunk-VCUFZB45.js";
11
+ import "./chunk-FACL3NXU.js";
12
+ import "./chunk-WONPNSSI.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.9.3",
3
+ "version": "2.9.5",
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/essence-spec": "2.0.1",
51
+ "@decantr/core": "2.1.0",
52
52
  "@decantr/registry": "2.2.0",
53
- "@decantr/verifier": "2.3.3",
54
53
  "@decantr/telemetry": "2.2.1",
55
- "@decantr/core": "2.1.0"
54
+ "@decantr/essence-spec": "2.0.1",
55
+ "@decantr/verifier": "2.3.3"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",