@decantr/cli 2.9.6 → 2.9.8

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
@@ -17,7 +17,7 @@ Or run it without installing:
17
17
  npx @decantr/cli new my-app --blueprint=esports-hq
18
18
  ```
19
19
 
20
- 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 next command.
20
+ 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.
21
21
  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
22
  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
23
  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` when you want project-owned UI patterns and local rules such as button/card/shell/theme standards to appear in future task context and verification.
@@ -96,6 +96,12 @@ Brownfield analysis also writes `.decantr/doctrine-map.json`, a ranked source-pr
96
96
  - syncs paginated hosted registry content into a full slug-keyed local cache for offline guards and context generation
97
97
  - validates, refreshes, and maintains `decantr.essence.json`
98
98
 
99
+ ## Security And Permissions
100
+
101
+ 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.
102
+
103
+ 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).
104
+
99
105
  ## Common Commands
100
106
 
101
107
  ```bash
@@ -136,11 +142,15 @@ decantr list patterns
136
142
  decantr showcase verification --json
137
143
  ```
138
144
 
145
+ `suggest --from-code` uses the selected app's source file to rank both hosted registry patterns and accepted project-owned local patterns, so Brownfield button/card/form law can surface from real code instead of just the text query.
146
+
139
147
  ## Project Health And Studio
140
148
 
141
149
  `decantr verify` is the workflow command most users should run locally after edits. It delegates to Project Health, can add Brownfield guard validation with `--brownfield`, requires an accepted local pattern pack with `--local-patterns`, scans `.decantr/rules.json` when present, supports workspace mode, and writes evidence to `.decantr/evidence/latest.json` by default when `--evidence` is used.
142
150
 
143
- `decantr doctor` explains project/workspace state, adoption mode, generated artifacts, local law, visual evidence, design authority signals, CI wiring, and the next command to run. It is the command to reach for when an app is in a monorepo, has stale Decantr files, or someone is not sure what Decantr expects next.
151
+ `decantr doctor` explains project/workspace state, adoption mode, generated artifacts, local law, visual evidence, design authority signals, CI wiring, and an ordered next-step queue. It is the command to reach for when an app is in a monorepo, has stale Decantr files, or someone is not sure what Decantr expects next.
152
+
153
+ `decantr setup` is non-mutating orientation. In an attached Brownfield app it reflects whether local law is already accepted, so the recommended verify command includes `--local-patterns` only when the project has that layer.
144
154
 
145
155
  `decantr ci` is the blessed non-mutating automation gate. It runs the Project Health surface with adoption-mode-aware local law checks and emits a schema-backed CI report. `decantr ci init` writes root GitHub workflows or portable generic snippets using the detected package manager and pinned local CLI command instead of `@latest`; if the root manifest has not pinned Decantr yet, it prints the exact install command first.
146
156
 
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-32H5SFKV.js";
3
- import "./chunk-RXF7ZYGK.js";
4
- import "./chunk-VCUFZB45.js";
5
- import "./chunk-FACL3NXU.js";
6
- import "./chunk-WONPNSSI.js";
2
+ import "./chunk-JSILTE5V.js";
3
+ import "./chunk-IQZCIMQJ.js";
4
+ import "./chunk-QDMXZSVK.js";
5
+ import "./chunk-WPP3JEMC.js";
6
+ import "./chunk-4SZ4SEKT.js";
@@ -1971,6 +1971,16 @@ var YELLOW = "\x1B[33m";
1971
1971
  var CYAN = "\x1B[36m";
1972
1972
  var RESET = "\x1B[0m";
1973
1973
  var DIM = "\x1B[2m";
1974
+ function isContractOnlyProject(projectRoot) {
1975
+ const metadataPath = join10(projectRoot, ".decantr", "project.json");
1976
+ if (!existsSync10(metadataPath)) return false;
1977
+ try {
1978
+ const metadata = JSON.parse(readFileSync10(metadataPath, "utf-8"));
1979
+ return metadata.initialized?.adoptionMode === "contract-only";
1980
+ } catch {
1981
+ return false;
1982
+ }
1983
+ }
1974
1984
  function collectCheckIssues(projectRoot = process.cwd(), options = {}) {
1975
1985
  const essencePath = join10(projectRoot, "decantr.essence.json");
1976
1986
  if (!existsSync10(essencePath)) {
@@ -2000,9 +2010,11 @@ function collectCheckIssues(projectRoot = process.cwd(), options = {}) {
2000
2010
  return { essence, issues, missingEssence: false };
2001
2011
  }
2002
2012
  let interactionIssues = [];
2003
- try {
2004
- interactionIssues = scanProjectInteractions(projectRoot);
2005
- } catch {
2013
+ if (!isContractOnlyProject(projectRoot)) {
2014
+ try {
2015
+ interactionIssues = scanProjectInteractions(projectRoot);
2016
+ } catch {
2017
+ }
2006
2018
  }
2007
2019
  try {
2008
2020
  const guardContext = buildGuardRegistryContext(projectRoot);
@@ -2066,9 +2078,16 @@ async function cmdHeal(projectRoot = process.cwd(), options = {}) {
2066
2078
  console.log(` ${DIM}Suggestion: ${issue.suggestion}${RESET}`);
2067
2079
  }
2068
2080
  }
2069
- console.log(`
2070
- ${YELLOW}Manual fixes required. Review the issues above.${RESET}`);
2071
2081
  const hasError = issues.some((i) => i.type === "error");
2082
+ if (hasError) {
2083
+ console.log(`
2084
+ ${YELLOW}Manual fixes required. Review the issues above.${RESET}`);
2085
+ } else {
2086
+ console.log(
2087
+ `
2088
+ ${YELLOW}Warnings found. Review the issues above or set stricter gates in CI.${RESET}`
2089
+ );
2090
+ }
2072
2091
  if (hasError) {
2073
2092
  process.exitCode = 1;
2074
2093
  }
@@ -277,7 +277,15 @@ async function syncRegistry(cacheDir, apiUrl = DEFAULT_API_URL) {
277
277
  }
278
278
 
279
279
  // src/scaffold.ts
280
- import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
280
+ import {
281
+ appendFileSync,
282
+ existsSync as existsSync2,
283
+ mkdirSync as mkdirSync2,
284
+ readdirSync as readdirSync2,
285
+ readFileSync as readFileSync2,
286
+ rmSync,
287
+ writeFileSync as writeFileSync2
288
+ } from "fs";
281
289
  import { dirname, join as join2 } from "path";
282
290
  import { fileURLToPath } from "url";
283
291
  import { compileExecutionPackBundle } from "@decantr/core";
@@ -4504,6 +4512,24 @@ function writeExecutionPackArtifacts(basePathWithoutExtension, pack) {
4504
4512
  writeFileSync2(jsonPath, JSON.stringify(pack, null, 2) + "\n");
4505
4513
  return markdownPath;
4506
4514
  }
4515
+ function isManagedExecutionPackArtifact(fileName) {
4516
+ return fileName === "pack-manifest.json" || /^(?:scaffold|review|section-.+-pack|page-.+-pack|mutation-.+-pack)\.(?:md|json)$/.test(
4517
+ fileName
4518
+ );
4519
+ }
4520
+ function removeObsoleteExecutionPackArtifacts(contextDir, writtenPaths) {
4521
+ const expected = /* @__PURE__ */ new Set();
4522
+ for (const path of writtenPaths) {
4523
+ expected.add(path);
4524
+ if (path.endsWith(".md")) expected.add(path.slice(0, -".md".length) + ".json");
4525
+ }
4526
+ for (const entry of readdirSync2(contextDir, { withFileTypes: true })) {
4527
+ if (!entry.isFile()) continue;
4528
+ if (!isManagedExecutionPackArtifact(entry.name)) continue;
4529
+ const fullPath = join2(contextDir, entry.name);
4530
+ if (!expected.has(fullPath)) rmSync(fullPath, { force: true });
4531
+ }
4532
+ }
4507
4533
  function writeExecutionPackBundleArtifacts(contextDir, bundle) {
4508
4534
  mkdirSync2(contextDir, { recursive: true });
4509
4535
  const outputPaths = [];
@@ -4540,6 +4566,7 @@ function writeExecutionPackBundleArtifacts(contextDir, bundle) {
4540
4566
  const manifestPath = join2(contextDir, "pack-manifest.json");
4541
4567
  writeFileSync2(manifestPath, JSON.stringify(bundle.manifest, null, 2) + "\n");
4542
4568
  outputPaths.push(manifestPath);
4569
+ removeObsoleteExecutionPackArtifacts(contextDir, outputPaths);
4543
4570
  return {
4544
4571
  paths: outputPaths,
4545
4572
  scaffoldPackPath,
@@ -14,7 +14,7 @@ import {
14
14
  scaffoldProject,
15
15
  syncRegistry,
16
16
  writeExecutionPackBundleArtifacts
17
- } from "./chunk-RXF7ZYGK.js";
17
+ } from "./chunk-IQZCIMQJ.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-VCUFZB45.js";
25
+ } from "./chunk-QDMXZSVK.js";
26
26
  import {
27
27
  createProjectHealthReport,
28
28
  formatProjectHealthMarkdown,
29
29
  formatProjectHealthText,
30
30
  resolveWorkspaceInfo,
31
31
  shouldFailHealth
32
- } from "./chunk-FACL3NXU.js";
32
+ } from "./chunk-WPP3JEMC.js";
33
33
  import {
34
34
  buildGuardRegistryContext,
35
35
  createDoctrineMap,
@@ -46,11 +46,11 @@ import {
46
46
  sendCliCommandTelemetry,
47
47
  sendNewProjectCompletedTelemetry,
48
48
  writeDoctrineMap
49
- } from "./chunk-WONPNSSI.js";
49
+ } from "./chunk-4SZ4SEKT.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";
53
- import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute3, join as join31, relative as relative7, resolve as resolve4 } from "path";
53
+ import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute3, join as join31, relative as relative7, resolve as resolve4 } from "path";
54
54
  import { fileURLToPath as fileURLToPath3 } from "url";
55
55
  import { evaluateGuard, isV4 as isV49, validateEssence as validateEssence2 } from "@decantr/essence-spec";
56
56
  import {
@@ -2754,7 +2754,7 @@ function writeBrownfieldIntelligenceArtifacts(input) {
2754
2754
 
2755
2755
  // src/detect.ts
2756
2756
  import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
2757
- import { join as join12 } from "path";
2757
+ import { dirname as dirname2, join as join12 } from "path";
2758
2758
  var RULE_FILES = [
2759
2759
  "CLAUDE.md",
2760
2760
  ".claude/rules",
@@ -2766,6 +2766,34 @@ var RULE_FILES = [
2766
2766
  ".github/copilot-instructions.md",
2767
2767
  ".windsurfrules"
2768
2768
  ];
2769
+ function readPackageJson(dir) {
2770
+ const path = join12(dir, "package.json");
2771
+ if (!existsSync10(path)) return null;
2772
+ try {
2773
+ return JSON.parse(readFileSync9(path, "utf-8"));
2774
+ } catch {
2775
+ return null;
2776
+ }
2777
+ }
2778
+ function packageManagerFromName(name) {
2779
+ if (name === "pnpm" || name === "yarn" || name === "bun" || name === "npm") return name;
2780
+ return "unknown";
2781
+ }
2782
+ function detectPackageManager(projectRoot) {
2783
+ let current = projectRoot;
2784
+ while (true) {
2785
+ const pkg = readPackageJson(current);
2786
+ const declared = packageManagerFromName(pkg?.packageManager?.split("@")[0]);
2787
+ if (declared !== "unknown") return declared;
2788
+ if (existsSync10(join12(current, "pnpm-lock.yaml"))) return "pnpm";
2789
+ if (existsSync10(join12(current, "yarn.lock"))) return "yarn";
2790
+ if (existsSync10(join12(current, "bun.lockb"))) return "bun";
2791
+ if (existsSync10(join12(current, "package-lock.json"))) return "npm";
2792
+ const parent = dirname2(current);
2793
+ if (parent === current) return "unknown";
2794
+ current = parent;
2795
+ }
2796
+ }
2769
2797
  function detectProject(projectRoot = process.cwd()) {
2770
2798
  const result = {
2771
2799
  framework: "unknown",
@@ -2782,15 +2810,7 @@ function detectProject(projectRoot = process.cwd()) {
2782
2810
  result.existingRuleFiles.push(ruleFile);
2783
2811
  }
2784
2812
  }
2785
- if (existsSync10(join12(projectRoot, "pnpm-lock.yaml"))) {
2786
- result.packageManager = "pnpm";
2787
- } else if (existsSync10(join12(projectRoot, "yarn.lock"))) {
2788
- result.packageManager = "yarn";
2789
- } else if (existsSync10(join12(projectRoot, "bun.lockb"))) {
2790
- result.packageManager = "bun";
2791
- } else if (existsSync10(join12(projectRoot, "package-lock.json"))) {
2792
- result.packageManager = "npm";
2793
- }
2813
+ result.packageManager = detectPackageManager(projectRoot);
2794
2814
  result.hasTypeScript = existsSync10(join12(projectRoot, "tsconfig.json"));
2795
2815
  result.hasTailwind = existsSync10(join12(projectRoot, "tailwind.config.js")) || existsSync10(join12(projectRoot, "tailwind.config.ts")) || existsSync10(join12(projectRoot, "tailwind.config.mjs")) || existsSync10(join12(projectRoot, "tailwind.config.cjs"));
2796
2816
  if (existsSync10(join12(projectRoot, "next.config.js")) || existsSync10(join12(projectRoot, "next.config.ts")) || existsSync10(join12(projectRoot, "next.config.mjs"))) {
@@ -3005,7 +3025,8 @@ var RESET2 = "\x1B[0m";
3005
3025
  var GREEN2 = "\x1B[32m";
3006
3026
  var CYAN = "\x1B[36m";
3007
3027
  var YELLOW2 = "\x1B[33m";
3008
- async function cmdAnalyze(projectRoot = process.cwd(), workspace) {
3028
+ async function cmdAnalyze(projectRoot = process.cwd(), workspace, options = {}) {
3029
+ const printNextStep = options.printNextStep ?? true;
3009
3030
  const startedAt = Date.now();
3010
3031
  console.log(`
3011
3032
  ${BOLD}Analyzing project...${RESET2}
@@ -3170,11 +3191,13 @@ ${DIM2}Written to:${RESET2} ${outputPath}`);
3170
3191
  console.log(`${DIM2}Brownfield intelligence:${RESET2} ${intelligenceArtifacts.intelligencePath}`);
3171
3192
  console.log(`${DIM2}Theme inventory:${RESET2} ${intelligenceArtifacts.themeInventoryPath}`);
3172
3193
  console.log(`${DIM2}Enrichment backlog:${RESET2} ${intelligenceArtifacts.backlogPath}`);
3173
- console.log(
3174
- `
3194
+ if (printNextStep) {
3195
+ console.log(
3196
+ `
3175
3197
  ${YELLOW2}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then run ${BOLD}${recommendedAttachCommand}${RESET2} to attach Decantr using the observed proposal.
3176
3198
  `
3177
- );
3199
+ );
3200
+ }
3178
3201
  await sendAnalyzeCompletedTelemetry({
3179
3202
  componentCount: components.componentCount,
3180
3203
  dependencyCategoryCount: [
@@ -3195,7 +3218,7 @@ ${YELLOW2}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then
3195
3218
 
3196
3219
  // src/commands/ci.ts
3197
3220
  import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
3198
- import { dirname as dirname2, join as join16, relative as relative4, resolve } from "path";
3221
+ import { dirname as dirname3, join as join16, relative as relative4, resolve } from "path";
3199
3222
 
3200
3223
  // src/local-law.ts
3201
3224
  import { execFileSync } from "child_process";
@@ -3732,7 +3755,7 @@ function parseProvider(value) {
3732
3755
  if (value === "github" || value === "generic") return value;
3733
3756
  throw new Error("Invalid --provider value. Use github or generic.");
3734
3757
  }
3735
- function detectPackageManager(root) {
3758
+ function detectPackageManager2(root) {
3736
3759
  const pkg = readJson(join16(root, "package.json"));
3737
3760
  const declared = pkg?.packageManager?.split("@")[0];
3738
3761
  if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
@@ -3801,7 +3824,7 @@ function projectSlug(projectPath) {
3801
3824
  }
3802
3825
  function writeOutput(root, path, content) {
3803
3826
  const absolute = resolve(root, path);
3804
- mkdirSync9(dirname2(absolute), { recursive: true });
3827
+ mkdirSync9(dirname3(absolute), { recursive: true });
3805
3828
  writeFileSync10(absolute, content, "utf-8");
3806
3829
  }
3807
3830
  function summarizeLocalLaw(projectRoot) {
@@ -3931,7 +3954,7 @@ function writeCiInit(root, options) {
3931
3954
  }
3932
3955
  const outputRoot = workspaceInfo.workspaceRoot;
3933
3956
  const projectPath = options.project ?? (options.workspace || workspaceInfo.appRoot === workspaceInfo.workspaceRoot ? void 0 : relative4(workspaceInfo.workspaceRoot, workspaceInfo.appRoot).replace(/\\/g, "/"));
3934
- const packageManager = detectPackageManager(outputRoot);
3957
+ const packageManager = detectPackageManager2(outputRoot);
3935
3958
  const command = decantrCommand(packageManager);
3936
3959
  const failOn = options.failOn ?? "error";
3937
3960
  const provider = options.provider ?? "github";
@@ -4295,7 +4318,7 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
4295
4318
 
4296
4319
  // src/commands/doctor.ts
4297
4320
  import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
4298
- import { dirname as dirname3, join as join18, relative as relative5 } from "path";
4321
+ import { dirname as dirname4, join as join18, relative as relative5 } from "path";
4299
4322
  import { fileURLToPath } from "url";
4300
4323
  import { isV4 as isV44 } from "@decantr/essence-spec";
4301
4324
  import { collectMissingPackManifestFiles } from "@decantr/verifier";
@@ -4319,16 +4342,16 @@ function isContractOnlyProject(projectRoot) {
4319
4342
  return projectJson?.initialized?.adoptionMode === "contract-only";
4320
4343
  }
4321
4344
  function readCliPackageVersion() {
4322
- const packagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4323
- const srcPackagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "package.json");
4345
+ const packagePath = join18(dirname4(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4346
+ const srcPackagePath = join18(dirname4(fileURLToPath(import.meta.url)), "..", "package.json");
4324
4347
  const pkg = readJson2(packagePath) ?? readJson2(srcPackagePath);
4325
4348
  return pkg?.version ?? "unknown";
4326
4349
  }
4327
- function readPackageJson(dir) {
4350
+ function readPackageJson2(dir) {
4328
4351
  return readJson2(join18(dir, "package.json"));
4329
4352
  }
4330
- function detectPackageManager2(root) {
4331
- const pkg = readPackageJson(root);
4353
+ function detectPackageManager3(root) {
4354
+ const pkg = readPackageJson2(root);
4332
4355
  const declared = pkg?.packageManager?.split("@")[0];
4333
4356
  if (declared === "pnpm" || declared === "npm" || declared === "yarn" || declared === "bun") {
4334
4357
  return declared;
@@ -4340,11 +4363,11 @@ function detectPackageManager2(root) {
4340
4363
  return "unknown";
4341
4364
  }
4342
4365
  function localCliDependency(root) {
4343
- const pkg = readPackageJson(root);
4366
+ const pkg = readPackageJson2(root);
4344
4367
  return pkg?.devDependencies?.["@decantr/cli"] ?? pkg?.dependencies?.["@decantr/cli"] ?? null;
4345
4368
  }
4346
4369
  function hasWorkspaceMarker2(root) {
4347
- const pkg = readPackageJson(root);
4370
+ const pkg = readPackageJson2(root);
4348
4371
  return Boolean(
4349
4372
  existsSync16(join18(root, "pnpm-workspace.yaml")) || existsSync16(join18(root, "turbo.json")) || existsSync16(join18(root, "nx.json")) || pkg?.workspaces
4350
4373
  );
@@ -4375,7 +4398,7 @@ function hasAnyFile(dir, names) {
4375
4398
  return null;
4376
4399
  }
4377
4400
  function packageHasDependency(dir, names) {
4378
- const pkg = readPackageJson(dir);
4401
+ const pkg = readPackageJson2(dir);
4379
4402
  const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
4380
4403
  return names.some((name) => Boolean(deps[name]));
4381
4404
  }
@@ -4442,6 +4465,10 @@ function statusFromIssues(issues, essenceVersion) {
4442
4465
  }
4443
4466
  return "healthy";
4444
4467
  }
4468
+ function appendUnique(commands, command) {
4469
+ if (!command) return;
4470
+ if (!commands.includes(command)) commands.push(command);
4471
+ }
4445
4472
  function buildDoctorReport(root, args) {
4446
4473
  let projectArg;
4447
4474
  for (let index = 1; index < args.length; index += 1) {
@@ -4455,7 +4482,7 @@ function buildDoctorReport(root, args) {
4455
4482
  const appRoot = workspaceMode ? workspaceRoot : workspaceInfo.appRoot;
4456
4483
  const projectMissing = Boolean(projectArg && !existsSync16(appRoot));
4457
4484
  const projectPath = appRoot === workspaceRoot ? null : rel(workspaceRoot, appRoot);
4458
- const packageManager = detectPackageManager2(workspaceRoot);
4485
+ const packageManager = detectPackageManager3(workspaceRoot);
4459
4486
  const cliDependency = localCliDependency(workspaceRoot);
4460
4487
  const detected = detectProject(appRoot);
4461
4488
  const projectJson = readJson2(join18(appRoot, ".decantr", "project.json"));
@@ -4475,6 +4502,8 @@ function buildDoctorReport(root, args) {
4475
4502
  const workflowMode = projectJson?.initialized?.workflowMode ?? null;
4476
4503
  const adoptionMode = projectJson?.initialized?.adoptionMode ?? null;
4477
4504
  const packHydrationOptional = adoptionMode === "contract-only";
4505
+ const localPatternsPresent = existsSync16(localPatternsPath(appRoot));
4506
+ const localRulesPresent = existsSync16(localRulesPath(appRoot));
4478
4507
  const missingPackReferences = workspaceMode ? projects.flatMap(
4479
4508
  (project) => collectMissingPackManifestFiles(join18(workspaceRoot, project.path)).map(
4480
4509
  (missing) => `${project.path}/${missing.relativePath}`
@@ -4567,7 +4596,7 @@ function buildDoctorReport(root, args) {
4567
4596
  nextCommand: "decantr registry compile-packs <app-path>/decantr.essence.json --write-context"
4568
4597
  });
4569
4598
  }
4570
- if (workflowMode === "brownfield-attach" && !existsSync16(localPatternsPath(appRoot))) {
4599
+ if (workflowMode === "brownfield-attach" && !localPatternsPresent) {
4571
4600
  issues.push({
4572
4601
  category: "local-law",
4573
4602
  severity: "info",
@@ -4595,7 +4624,39 @@ function buildDoctorReport(root, args) {
4595
4624
  issues,
4596
4625
  workspaceMode || workspaceInfo.requiresProjectSelection ? "4.0.0" : essenceVersion
4597
4626
  );
4598
- const recommendedNextCommand = issues.find((issue) => issue.category === "workspace" && issue.nextCommand)?.nextCommand ?? issues.find((issue) => issue.nextCommand)?.nextCommand ?? (workspaceMode ? "decantr ci --workspace" : projectPath ? `decantr ci --project ${projectPath}` : "decantr ci");
4627
+ const projectFlag = projectPath ? ` --project ${projectPath}` : "";
4628
+ const verifyCommand = workflowMode === "brownfield-attach" ? `decantr verify --brownfield --local-patterns${projectFlag}` : workspaceMode ? "decantr ci --workspace" : `decantr verify${projectFlag}`;
4629
+ const ciCommand = workspaceMode ? "decantr ci --workspace --fail-on error" : `decantr ci${projectFlag} --fail-on error`;
4630
+ const recommendedNextCommands = [];
4631
+ const blockingIssue = issues.find((issue) => issue.category === "workspace" && issue.nextCommand) ?? issues.find(
4632
+ (issue) => (issue.category === "setup" || issue.category === "migration") && issue.nextCommand
4633
+ );
4634
+ if (blockingIssue) {
4635
+ appendUnique(recommendedNextCommands, blockingIssue.nextCommand);
4636
+ } else {
4637
+ appendUnique(
4638
+ recommendedNextCommands,
4639
+ issues.find((issue) => issue.category === "ci" && issue.message.includes("not pinned"))?.nextCommand
4640
+ );
4641
+ if (workflowMode === "brownfield-attach" && !localPatternsPresent) {
4642
+ appendUnique(recommendedNextCommands, `decantr codify --from-audit${projectFlag}`);
4643
+ appendUnique(recommendedNextCommands, `decantr codify --accept${projectFlag}`);
4644
+ }
4645
+ appendUnique(
4646
+ recommendedNextCommands,
4647
+ issues.find((issue) => issue.category === "generated-artifact")?.nextCommand
4648
+ );
4649
+ appendUnique(
4650
+ recommendedNextCommands,
4651
+ issues.find((issue) => issue.category === "ci" && issue.message.includes("No Decantr CI"))?.nextCommand
4652
+ );
4653
+ if (workflowMode === "brownfield-attach") {
4654
+ appendUnique(recommendedNextCommands, `decantr task <route> "<change>"${projectFlag}`);
4655
+ }
4656
+ appendUnique(recommendedNextCommands, verifyCommand);
4657
+ appendUnique(recommendedNextCommands, ciCommand);
4658
+ }
4659
+ const recommendedNextCommand = recommendedNextCommands[0] ?? ciCommand;
4599
4660
  return {
4600
4661
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4601
4662
  workspaceRoot,
@@ -4627,8 +4688,8 @@ function buildDoctorReport(root, args) {
4627
4688
  missingReferencedFiles: missingPackReferences.slice(0, 25)
4628
4689
  },
4629
4690
  localLaw: {
4630
- patternsPresent: existsSync16(localPatternsPath(appRoot)),
4631
- rulesPresent: existsSync16(localRulesPath(appRoot))
4691
+ patternsPresent: localPatternsPresent,
4692
+ rulesPresent: localRulesPresent
4632
4693
  },
4633
4694
  visualEvidence: {
4634
4695
  manifestPresent: existsSync16(join18(appRoot, ".decantr", "evidence", "visual-manifest.json"))
@@ -4636,7 +4697,8 @@ function buildDoctorReport(root, args) {
4636
4697
  designAuthority,
4637
4698
  status,
4638
4699
  issues,
4639
- recommendedNextCommand
4700
+ recommendedNextCommand,
4701
+ recommendedNextCommands
4640
4702
  };
4641
4703
  }
4642
4704
  function colorForStatus(status) {
@@ -4693,13 +4755,20 @@ function formatDoctorText(report) {
4693
4755
  if (issue.nextCommand) lines.push(` ${DIM4}${issue.nextCommand}${RESET4}`);
4694
4756
  }
4695
4757
  }
4696
- lines.push("", `${BOLD3}Next:${RESET4}`, ` ${report.recommendedNextCommand}`, "");
4758
+ lines.push("", `${BOLD3}Next steps:${RESET4}`);
4759
+ for (const [index, command] of report.recommendedNextCommands.entries()) {
4760
+ lines.push(` ${index + 1}. ${command}`);
4761
+ }
4762
+ if (report.recommendedNextCommands.length === 0) {
4763
+ lines.push(` ${report.recommendedNextCommand}`);
4764
+ }
4765
+ lines.push("");
4697
4766
  return `${lines.join("\n")}
4698
4767
  `;
4699
4768
  }
4700
4769
  function cmdDoctorHelp() {
4701
4770
  console.log(`
4702
- ${BOLD3}decantr doctor${RESET4} \u2014 Explain Decantr state and the next command to run
4771
+ ${BOLD3}decantr doctor${RESET4} \u2014 Explain Decantr state and the next commands to run
4703
4772
 
4704
4773
  ${BOLD3}Usage:${RESET4}
4705
4774
  decantr doctor [--project <path>] [--workspace] [--json]
@@ -4723,7 +4792,7 @@ async function cmdDoctor(args = ["doctor"], root = process.cwd()) {
4723
4792
 
4724
4793
  // src/commands/export.ts
4725
4794
  import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
4726
- import { dirname as dirname4, isAbsolute, join as join19 } from "path";
4795
+ import { dirname as dirname5, isAbsolute, join as join19 } from "path";
4727
4796
  var GREEN5 = "\x1B[32m";
4728
4797
  var RED4 = "\x1B[31m";
4729
4798
  var DIM5 = "\x1B[2m";
@@ -4977,7 +5046,7 @@ async function cmdExport(target, projectRoot, options = {}) {
4977
5046
  }
4978
5047
  }
4979
5048
  function ensureDir(filePath) {
4980
- const dir = dirname4(filePath);
5049
+ const dir = dirname5(filePath);
4981
5050
  if (!existsSync17(dir)) {
4982
5051
  mkdirSync11(dir, { recursive: true });
4983
5052
  }
@@ -5890,7 +5959,7 @@ async function cmdNewProject(projectName, options) {
5890
5959
  )
5891
5960
  );
5892
5961
  }
5893
- const packageManager = detectPackageManager3();
5962
+ const packageManager = detectPackageManager4();
5894
5963
  if (shouldBootstrapRuntime) {
5895
5964
  console.log(heading("Installing dependencies..."));
5896
5965
  try {
@@ -5966,7 +6035,7 @@ ${YELLOW6}Decantr init encountered issues. Run \`decantr init\` manually inside
5966
6035
  });
5967
6036
  }
5968
6037
  }
5969
- function detectPackageManager3() {
6038
+ function detectPackageManager4() {
5970
6039
  if (existsSync21(join23(process.cwd(), "pnpm-lock.yaml")) || existsSync21(join23(process.cwd(), "pnpm-workspace.yaml"))) {
5971
6040
  return "pnpm";
5972
6041
  }
@@ -6365,6 +6434,7 @@ import { join as join27 } from "path";
6365
6434
  import { isV4 as isV47 } from "@decantr/essence-spec";
6366
6435
  var GREEN11 = "\x1B[32m";
6367
6436
  var RED9 = "\x1B[31m";
6437
+ var YELLOW8 = "\x1B[33m";
6368
6438
  var DIM11 = "\x1B[2m";
6369
6439
  var RESET11 = "\x1B[0m";
6370
6440
  function readV4Essence2(projectRoot) {
@@ -6403,6 +6473,27 @@ function readFlagValue2(args, name) {
6403
6473
  }
6404
6474
  return void 0;
6405
6475
  }
6476
+ function resolveSectionAlias(sections, requestedSectionId) {
6477
+ const exact = sections.find((section) => section.id === requestedSectionId);
6478
+ if (exact) return { section: exact, resolvedFromAlias: false };
6479
+ const roleByAlias = {
6480
+ app: "primary",
6481
+ main: "primary",
6482
+ primary: "primary",
6483
+ public: "public",
6484
+ marketing: "public",
6485
+ auth: "gateway",
6486
+ gateway: "gateway",
6487
+ auxiliary: "auxiliary"
6488
+ };
6489
+ const desiredRole = roleByAlias[requestedSectionId.toLowerCase()];
6490
+ if (!desiredRole) return null;
6491
+ const roleMatches = sections.filter((section) => section.role === desiredRole);
6492
+ if (roleMatches.length === 1) return { section: roleMatches[0], resolvedFromAlias: true };
6493
+ if (roleMatches.length > 1) return null;
6494
+ const observedMatch = sections.find((section) => section.id === `observed-${desiredRole}`);
6495
+ return observedMatch ? { section: observedMatch, resolvedFromAlias: true } : null;
6496
+ }
6406
6497
  function recomputeGlobalFeatures(essence) {
6407
6498
  const all = /* @__PURE__ */ new Set();
6408
6499
  for (const section of essence.blueprint.sections || []) {
@@ -6467,24 +6558,31 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6467
6558
  if (!loaded) return;
6468
6559
  const { essence, essencePath } = loaded;
6469
6560
  const sections = essence.blueprint.sections;
6470
- const section = sections.find((s) => s.id === sectionId);
6471
- if (!section) {
6561
+ const resolved = resolveSectionAlias(sections, sectionId);
6562
+ if (!resolved) {
6472
6563
  console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6473
6564
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6474
6565
  process.exitCode = 1;
6475
6566
  return;
6476
6567
  }
6568
+ const { section } = resolved;
6569
+ const resolvedSectionId = section.id;
6477
6570
  const pageIdx = section.pages.findIndex((p) => p.id === pageId);
6478
6571
  if (pageIdx === -1) {
6479
- console.error(`${RED9}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6572
+ console.error(`${RED9}Page "${pageId}" not found in section "${resolvedSectionId}".${RESET11}`);
6480
6573
  console.error(`${DIM11}Available pages: ${section.pages.map((p) => p.id).join(", ")}${RESET11}`);
6481
6574
  process.exitCode = 1;
6482
6575
  return;
6483
6576
  }
6484
6577
  section.pages.splice(pageIdx, 1);
6485
- removeRoutes(essence, sectionId, pageId);
6578
+ removeRoutes(essence, resolvedSectionId, pageId);
6486
6579
  writeEssence2(essencePath, essence);
6487
- console.log(`${GREEN11}Removed page "${pageId}" from section "${sectionId}".${RESET11}`);
6580
+ if (resolved.resolvedFromAlias) {
6581
+ console.log(
6582
+ `${YELLOW8}Resolved section alias "${sectionId}" to "${resolvedSectionId}".${RESET11}`
6583
+ );
6584
+ }
6585
+ console.log(`${GREEN11}Removed page "${pageId}" from section "${resolvedSectionId}".${RESET11}`);
6488
6586
  const registryClient = new RegistryClient({
6489
6587
  cacheDir: join27(projectRoot, ".decantr", "cache")
6490
6588
  });
@@ -6504,13 +6602,18 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6504
6602
  sectionId = readFlagValue2(args, "section");
6505
6603
  if (sectionId) {
6506
6604
  const sections = essence.blueprint.sections;
6507
- const section = sections.find((s) => s.id === sectionId);
6508
- if (!section) {
6605
+ const resolved = resolveSectionAlias(sections, sectionId);
6606
+ if (!resolved) {
6509
6607
  console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6510
6608
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6511
6609
  process.exitCode = 1;
6512
6610
  return;
6513
6611
  }
6612
+ const { section } = resolved;
6613
+ if (resolved.resolvedFromAlias) {
6614
+ console.log(`${YELLOW8}Resolved section alias "${sectionId}" to "${section.id}".${RESET11}`);
6615
+ }
6616
+ sectionId = section.id;
6514
6617
  const fIdx = section.features.indexOf(feature);
6515
6618
  if (fIdx !== -1) {
6516
6619
  section.features.splice(fIdx, 1);
@@ -6535,7 +6638,7 @@ import { existsSync as existsSync26, readFileSync as readFileSync19, writeFileSy
6535
6638
  import { join as join28 } from "path";
6536
6639
  var GREEN12 = "\x1B[32m";
6537
6640
  var RED10 = "\x1B[31m";
6538
- var YELLOW8 = "\x1B[33m";
6641
+ var YELLOW9 = "\x1B[33m";
6539
6642
  var RESET12 = "\x1B[0m";
6540
6643
  var DIM12 = "\x1B[2m";
6541
6644
  var BOLD6 = "\x1B[1m";
@@ -6576,7 +6679,7 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6576
6679
  `);
6577
6680
  for (let i = 0; i < unresolved.length; i++) {
6578
6681
  const entry = unresolved[i];
6579
- const severityColor = entry.severity === "error" ? RED10 : YELLOW8;
6682
+ const severityColor = entry.severity === "error" ? RED10 : YELLOW9;
6580
6683
  const icon = entry.severity === "error" ? "x" : "!";
6581
6684
  console.log(
6582
6685
  ` ${severityColor}${icon}${RESET12} ${BOLD6}#${i + 1}${RESET12} [${entry.rule}] ${entry.message}`
@@ -6860,7 +6963,7 @@ import { join as join29 } from "path";
6860
6963
  import { isV4 as isV48 } from "@decantr/essence-spec";
6861
6964
  var GREEN14 = "\x1B[32m";
6862
6965
  var RED11 = "\x1B[31m";
6863
- var YELLOW9 = "\x1B[33m";
6966
+ var YELLOW10 = "\x1B[33m";
6864
6967
  var DIM14 = "\x1B[2m";
6865
6968
  var RESET14 = "\x1B[0m";
6866
6969
  var VALID_THEME_SHAPES = ["sharp", "rounded", "pill"];
@@ -6955,7 +7058,7 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6955
7058
  console.log(
6956
7059
  `${GREEN14}Derived files refreshed (tokens.css, treatments.css, all contexts).${RESET14}`
6957
7060
  );
6958
- console.log(`${YELLOW9}Guard will flag code using old tokens. Run \`decantr check\`.${RESET14}`);
7061
+ console.log(`${YELLOW10}Guard will flag code using old tokens. Run \`decantr check\`.${RESET14}`);
6959
7062
  }
6960
7063
 
6961
7064
  // src/prompts.ts
@@ -6964,7 +7067,7 @@ var BOLD8 = "\x1B[1m";
6964
7067
  var DIM15 = "\x1B[2m";
6965
7068
  var RESET15 = "\x1B[0m";
6966
7069
  var GREEN15 = "\x1B[32m";
6967
- var YELLOW10 = "\x1B[33m";
7070
+ var YELLOW11 = "\x1B[33m";
6968
7071
  var CYAN8 = "\x1B[36m";
6969
7072
  function ask(question, defaultValue) {
6970
7073
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -7004,7 +7107,7 @@ async function confirm(question, defaultYes = true) {
7004
7107
  }
7005
7108
  function warn(message) {
7006
7109
  console.log(`
7007
- ${YELLOW10} Warning: ${message}${RESET15}`);
7110
+ ${YELLOW11} Warning: ${message}${RESET15}`);
7008
7111
  }
7009
7112
  function showDetection(detected) {
7010
7113
  console.log(`
@@ -7023,7 +7126,7 @@ ${CYAN8}Detected project configuration:${RESET15}`);
7023
7126
  console.log(` Tailwind CSS: ${GREEN15}yes${RESET15}`);
7024
7127
  }
7025
7128
  if (detected.existingEssence) {
7026
- console.log(` Existing essence: ${YELLOW10}yes${RESET15}`);
7129
+ console.log(` Existing essence: ${YELLOW11}yes${RESET15}`);
7027
7130
  }
7028
7131
  }
7029
7132
  async function runInteractivePrompts(detected, archetypes, blueprints, themes, workflowSeed) {
@@ -7425,7 +7528,7 @@ var RESET16 = "\x1B[0m";
7425
7528
  var RED12 = "\x1B[31m";
7426
7529
  var GREEN16 = "\x1B[32m";
7427
7530
  var CYAN9 = "\x1B[36m";
7428
- var YELLOW11 = "\x1B[33m";
7531
+ var YELLOW12 = "\x1B[33m";
7429
7532
  function heading2(text) {
7430
7533
  return `
7431
7534
  ${BOLD9}${text}${RESET16}
@@ -8207,7 +8310,7 @@ async function compileHostedExecutionPackBundle(essencePath, namespace) {
8207
8310
  }
8208
8311
  const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
8209
8312
  const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
8210
- const contextDir = join31(dirname5(resolvedPath), ".decantr", "context");
8313
+ const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
8211
8314
  return { resolvedPath, bundle, contextDir };
8212
8315
  }
8213
8316
  function writeHostedExecutionPackContextArtifacts(contextDir, bundle) {
@@ -8251,7 +8354,7 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
8251
8354
  );
8252
8355
  let writtenContextDir = null;
8253
8356
  if (writeContext) {
8254
- const contextDir = join31(dirname5(resolvedPath), ".decantr", "context");
8357
+ const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
8255
8358
  mkdirSync16(contextDir, { recursive: true });
8256
8359
  writeFileSync19(
8257
8360
  join31(contextDir, "pack-manifest.json"),
@@ -8297,7 +8400,7 @@ async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutp
8297
8400
  );
8298
8401
  let writtenContextDir = null;
8299
8402
  if (writeContext) {
8300
- const contextDir = join31(dirname5(resolvedPath), ".decantr", "context");
8403
+ const contextDir = join31(dirname6(resolvedPath), ".decantr", "context");
8301
8404
  mkdirSync16(contextDir, { recursive: true });
8302
8405
  writeFileSync19(join31(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
8303
8406
  writtenContextDir = contextDir;
@@ -8468,7 +8571,7 @@ function printBlueprintPortfolioNotice(blueprint) {
8468
8571
  if (!portfolio) return;
8469
8572
  if (portfolio.visibility === "hidden" || portfolio.maturity === "fold-candidate") {
8470
8573
  console.log(
8471
- `${YELLOW11} Warning:${RESET16} blueprint "${blueprint.id}" is folded out of public browsing.`
8574
+ `${YELLOW12} Warning:${RESET16} blueprint "${blueprint.id}" is folded out of public browsing.`
8472
8575
  );
8473
8576
  if (portfolio.recommended_alternative) {
8474
8577
  console.log(
@@ -8481,7 +8584,7 @@ function printBlueprintPortfolioNotice(blueprint) {
8481
8584
  }
8482
8585
  if (portfolio.visibility === "labs") {
8483
8586
  console.log(
8484
- `${YELLOW11} Note:${RESET16} blueprint "${blueprint.id}" is a Labs blueprint; direct scaffolding is supported, but it is not a default recommendation yet.`
8587
+ `${YELLOW12} Note:${RESET16} blueprint "${blueprint.id}" is a Labs blueprint; direct scaffolding is supported, but it is not a default recommendation yet.`
8485
8588
  );
8486
8589
  }
8487
8590
  }
@@ -8668,7 +8771,10 @@ async function cmdSuggest(query, options = {}) {
8668
8771
  `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
8669
8772
  )
8670
8773
  );
8671
- const localMatches = localPatternMatches(options.projectRoot, query);
8774
+ const localMatches = localPatternMatches(
8775
+ options.projectRoot,
8776
+ [query, code].filter(Boolean).join("\n")
8777
+ );
8672
8778
  if (localMatches.length > 0) {
8673
8779
  console.log(`${BOLD9}Project-owned local law:${RESET16}`);
8674
8780
  for (const match of localMatches) {
@@ -8770,7 +8876,7 @@ async function cmdValidate(path) {
8770
8876
  console.log(heading2("Guard violations:"));
8771
8877
  for (const v of violations) {
8772
8878
  const vr = v;
8773
- console.log(` ${YELLOW11}[${vr.rule}]${RESET16} ${vr.message}`);
8879
+ console.log(` ${YELLOW12}[${vr.rule}]${RESET16} ${vr.message}`);
8774
8880
  if (vr.suggestion) {
8775
8881
  console.log(` ${DIM16}Suggestion: ${vr.suggestion}${RESET16}`);
8776
8882
  }
@@ -8876,7 +8982,7 @@ ${CYAN9}Telemetry enabled.${RESET16} Decantr will send privacy-filtered CLI prod
8876
8982
  console.log(`${DIM16}Set "telemetry": false in .decantr/project.json to opt out.${RESET16}`);
8877
8983
  }
8878
8984
  function readCliPackageVersion2() {
8879
- const here = dirname5(fileURLToPath3(import.meta.url));
8985
+ const here = dirname6(fileURLToPath3(import.meta.url));
8880
8986
  const candidates = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
8881
8987
  for (const candidate of candidates) {
8882
8988
  try {
@@ -9104,7 +9210,7 @@ async function cmdInit(args) {
9104
9210
  console.log(dim3(" Found .decantr/init-seed.json brownfield guidance."));
9105
9211
  }
9106
9212
  if (detected.existingEssence && !args.existing) {
9107
- console.log(`${YELLOW11}Warning: decantr.essence.json already exists.${RESET16}`);
9213
+ console.log(`${YELLOW12}Warning: decantr.essence.json already exists.${RESET16}`);
9108
9214
  const overwrite = await confirm("Overwrite existing configuration?", false);
9109
9215
  if (!overwrite) {
9110
9216
  console.log(dim3("Cancelled."));
@@ -9207,7 +9313,7 @@ async function cmdInit(args) {
9207
9313
  } else if (shouldUseRegistry && !apiAvailable) {
9208
9314
  if (!args.blueprint) {
9209
9315
  console.log(`
9210
- ${YELLOW11}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9316
+ ${YELLOW12}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9211
9317
  console.log(
9212
9318
  dim3("Run `decantr sync` or `decantr upgrade` when online to pull full registry content.\n")
9213
9319
  );
@@ -9256,7 +9362,7 @@ ${YELLOW11}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
9256
9362
  return;
9257
9363
  }
9258
9364
  console.log(`
9259
- ${YELLOW11}You're offline. Scaffolding Decantr default.${RESET16}`);
9365
+ ${YELLOW12}You're offline. Scaffolding Decantr default.${RESET16}`);
9260
9366
  console.log(dim3("Run `decantr upgrade` when online, or visit decantr.ai/registry\n"));
9261
9367
  selectedBlueprint = "default";
9262
9368
  } else if (shouldUseRegistry) {
@@ -9438,7 +9544,7 @@ ${YELLOW11}You're offline. Scaffolding Decantr default.${RESET16}`);
9438
9544
  return;
9439
9545
  }
9440
9546
  console.log(
9441
- `${YELLOW11} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET16}`
9547
+ `${YELLOW12} Warning: Could not fetch blueprint "${options.blueprint}". Using defaults.${RESET16}`
9442
9548
  );
9443
9549
  }
9444
9550
  } else if (shouldUseRegistry && options.archetype) {
@@ -9453,7 +9559,7 @@ ${YELLOW11}You're offline. Scaffolding Decantr default.${RESET16}`);
9453
9559
  return;
9454
9560
  }
9455
9561
  console.log(
9456
- `${YELLOW11} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET16}`
9562
+ `${YELLOW12} Warning: Could not fetch archetype "${options.archetype}". Using defaults.${RESET16}`
9457
9563
  );
9458
9564
  }
9459
9565
  }
@@ -9470,7 +9576,7 @@ ${YELLOW11}You're offline. Scaffolding Decantr default.${RESET16}`);
9470
9576
  return;
9471
9577
  }
9472
9578
  console.log(
9473
- `${YELLOW11} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET16}`
9579
+ `${YELLOW12} Warning: Could not fetch theme "${options.theme}". Using defaults.${RESET16}`
9474
9580
  );
9475
9581
  }
9476
9582
  }
@@ -9675,7 +9781,7 @@ async function cmdStatus(projectRoot = process.cwd()) {
9675
9781
  ` Guard: ${v4.meta.guard.mode} (DNA: ${v4.meta.guard.dna_enforcement}, Blueprint: ${v4.meta.guard.blueprint_enforcement})`
9676
9782
  );
9677
9783
  } else {
9678
- console.log(` ${YELLOW11}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9784
+ console.log(` ${YELLOW12}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9679
9785
  }
9680
9786
  } catch (e) {
9681
9787
  console.log(` ${RED12}Error reading essence: ${e.message}${RESET16}`);
@@ -9688,15 +9794,15 @@ async function cmdStatus(projectRoot = process.cwd()) {
9688
9794
  const syncStatus = projectJson.sync?.status || "unknown";
9689
9795
  const lastSync = projectJson.sync?.lastSync || "never";
9690
9796
  const source = projectJson.sync?.registrySource || "unknown";
9691
- const statusColor = syncStatus === "synced" ? GREEN16 : YELLOW11;
9797
+ const statusColor = syncStatus === "synced" ? GREEN16 : YELLOW12;
9692
9798
  console.log(` Status: ${statusColor}${syncStatus}${RESET16}`);
9693
9799
  console.log(` Last sync: ${dim3(lastSync)}`);
9694
9800
  console.log(` Source: ${dim3(source)}`);
9695
9801
  } catch {
9696
- console.log(` ${YELLOW11}Could not read project.json${RESET16}`);
9802
+ console.log(` ${YELLOW12}Could not read project.json${RESET16}`);
9697
9803
  }
9698
9804
  } else {
9699
- console.log(` ${YELLOW11}No .decantr/project.json found${RESET16}`);
9805
+ console.log(` ${YELLOW12}No .decantr/project.json found${RESET16}`);
9700
9806
  console.log(dim3(' Run "decantr init" to create project files.'));
9701
9807
  }
9702
9808
  }
@@ -9709,12 +9815,12 @@ async function cmdSync() {
9709
9815
  console.log(success3("Sync completed successfully."));
9710
9816
  console.log(` Synced: ${result.synced.join(", ")}`);
9711
9817
  if (result.failed.length > 0) {
9712
- console.log(` ${YELLOW11}Failed: ${result.failed.join(", ")}${RESET16}`);
9818
+ console.log(` ${YELLOW12}Failed: ${result.failed.join(", ")}${RESET16}`);
9713
9819
  }
9714
9820
  } else {
9715
- console.log(`${YELLOW11}Could not sync: API unavailable${RESET16}`);
9821
+ console.log(`${YELLOW12}Could not sync: API unavailable${RESET16}`);
9716
9822
  if (result.failed.length > 0) {
9717
- console.log(` ${YELLOW11}Failed: ${result.failed.join(", ")}${RESET16}`);
9823
+ console.log(` ${YELLOW12}Failed: ${result.failed.join(", ")}${RESET16}`);
9718
9824
  }
9719
9825
  }
9720
9826
  }
@@ -9724,7 +9830,7 @@ function printVerificationFindings(findings) {
9724
9830
  return;
9725
9831
  }
9726
9832
  for (const finding of findings) {
9727
- const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW11 : CYAN9;
9833
+ const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW12 : CYAN9;
9728
9834
  console.log(
9729
9835
  ` ${color}[${finding.severity.toUpperCase()}]${RESET16} ${finding.category}: ${finding.message}`
9730
9836
  );
@@ -10231,16 +10337,21 @@ async function cmdSetupWorkflow(args) {
10231
10337
  console.log(` Detected: ${formatDetection(detected)}`);
10232
10338
  console.log("");
10233
10339
  if (detected.existingEssence) {
10340
+ const hasLocalPatterns = existsSync29(localPatternsPath(workspaceInfo.appRoot));
10341
+ const hasLocalRules = existsSync29(localRulesPath(workspaceInfo.appRoot));
10342
+ const verifyCommand = hasLocalPatterns || hasLocalRules ? "decantr verify --brownfield --local-patterns" : "decantr verify --brownfield";
10234
10343
  console.log(`${BOLD9}Recommended path:${RESET16} maintain an attached Decantr project`);
10235
10344
  console.log(
10236
10345
  ` ${cyan3(withProject('decantr task <route> "<change>"', projectArg))} Prepare LLM context before edits`
10237
10346
  );
10238
10347
  console.log(
10239
- ` ${cyan3(withProject("decantr verify --brownfield", projectArg))} Run local health and drift checks`
10240
- );
10241
- console.log(
10242
- ` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose project-owned local law`
10348
+ ` ${cyan3(withProject(verifyCommand, projectArg))} Run local health and drift checks`
10243
10349
  );
10350
+ if (!hasLocalPatterns || !hasLocalRules) {
10351
+ console.log(
10352
+ ` ${cyan3(withProject("decantr codify --from-audit", projectArg))} Propose project-owned local law`
10353
+ );
10354
+ }
10244
10355
  return;
10245
10356
  }
10246
10357
  if (hasFootprint) {
@@ -10337,8 +10448,10 @@ async function cmdAdoptWorkflow(args) {
10337
10448
  return;
10338
10449
  }
10339
10450
  }
10340
- await cmdAnalyze(projectRoot, workspaceInfo);
10451
+ await cmdAnalyze(projectRoot, workspaceInfo, { printNextStep: false });
10341
10452
  if (process.exitCode && process.exitCode !== 0) return;
10453
+ const initCommand = projectArg ? `decantr init --project ${projectArg} --existing ${proposalFlag}` : `decantr init --existing ${proposalFlag}`;
10454
+ console.log(dim3(`Analysis artifacts written; continuing with ${initCommand}.`));
10342
10455
  await cmdInit({
10343
10456
  existing: true,
10344
10457
  yes: true,
@@ -10365,7 +10478,7 @@ async function cmdAdoptWorkflow(args) {
10365
10478
  )
10366
10479
  );
10367
10480
  } catch (e) {
10368
- console.log(`${YELLOW11}Pack hydration skipped:${RESET16} ${e.message}`);
10481
+ console.log(`${YELLOW12}Pack hydration skipped:${RESET16} ${e.message}`);
10369
10482
  console.log(
10370
10483
  dim3(
10371
10484
  `Run ${compilePacksCommandForProject(projectArg)} after adoption if you want hosted page/review packs.`
@@ -10376,7 +10489,7 @@ async function cmdAdoptWorkflow(args) {
10376
10489
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
10377
10490
  }
10378
10491
  if (runVerify) {
10379
- const { cmdHealth } = await import("./health-R7AV5G4V.js");
10492
+ const { cmdHealth } = await import("./health-VAYRQVTF.js");
10380
10493
  await cmdHealth(projectRoot, {
10381
10494
  browser: runBrowser,
10382
10495
  browserBaseUrl: baseUrl,
@@ -10447,7 +10560,7 @@ async function cmdVerifyWorkflow(args) {
10447
10560
  return;
10448
10561
  }
10449
10562
  if (workspaceMode) {
10450
- const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
10563
+ const { cmdWorkspace } = await import("./workspace-PBO3BJRL.js");
10451
10564
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
10452
10565
  return;
10453
10566
  }
@@ -10480,7 +10593,7 @@ async function cmdVerifyWorkflow(args) {
10480
10593
  }
10481
10594
  let guardExitCode;
10482
10595
  if (brownfield) {
10483
- const { cmdHeal, collectCheckIssues } = await import("./heal-ZQHEHBUJ.js");
10596
+ const { cmdHeal, collectCheckIssues } = await import("./heal-2UCSPRTK.js");
10484
10597
  if (quietOutput) {
10485
10598
  const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
10486
10599
  guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
@@ -10490,7 +10603,7 @@ async function cmdVerifyWorkflow(args) {
10490
10603
  process.exitCode = void 0;
10491
10604
  }
10492
10605
  }
10493
- const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
10606
+ const { cmdHealth, parseHealthArgs } = await import("./health-VAYRQVTF.js");
10494
10607
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10495
10608
  if (localPatterns) {
10496
10609
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10498,7 +10611,7 @@ async function cmdVerifyWorkflow(args) {
10498
10611
  if (!quietOutput) {
10499
10612
  console.log("");
10500
10613
  console.log(
10501
- `${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))}.`
10614
+ `${YELLOW12}Local pattern pack missing.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))}, review the proposal, then run ${cyan3(withProject("decantr codify --accept", projectArg))}.`
10502
10615
  );
10503
10616
  }
10504
10617
  process.exitCode = process.exitCode || 1;
@@ -10514,11 +10627,11 @@ async function cmdVerifyWorkflow(args) {
10514
10627
  console.log(`${GREEN16}Local rule manifest found:${RESET16} ${validation.rulesPath}`);
10515
10628
  } else {
10516
10629
  console.log(
10517
- `${YELLOW11}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
10630
+ `${YELLOW12}Local rule manifest missing.${RESET16} Run ${cyan3("decantr codify --from-audit")} to propose .decantr/rules.json.`
10518
10631
  );
10519
10632
  }
10520
10633
  for (const warning of validation.warnings.slice(0, 8)) {
10521
- console.log(`${YELLOW11}warn${RESET16} ${warning}`);
10634
+ console.log(`${YELLOW12}warn${RESET16} ${warning}`);
10522
10635
  }
10523
10636
  if (validation.findings.length > 0) {
10524
10637
  console.log("");
@@ -10671,7 +10784,7 @@ async function cmdTaskWorkflow(args) {
10671
10784
  console.log("");
10672
10785
  console.log(`${BOLD9}Project-owned local law:${RESET16}`);
10673
10786
  console.log(
10674
- ` ${YELLOW11}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
10787
+ ` ${YELLOW12}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
10675
10788
  );
10676
10789
  }
10677
10790
  if (context.changedFiles.length > 0) {
@@ -11316,7 +11429,7 @@ async function main() {
11316
11429
  }
11317
11430
  if (command === "--version" || command === "-v" || command === "version") {
11318
11431
  try {
11319
- const here = dirname5(fileURLToPath3(import.meta.url));
11432
+ const here = dirname6(fileURLToPath3(import.meta.url));
11320
11433
  const candidates = [join31(here, "..", "package.json"), join31(here, "..", "..", "package.json")];
11321
11434
  for (const candidate of candidates) {
11322
11435
  if (existsSync29(candidate)) {
@@ -11458,7 +11571,7 @@ async function main() {
11458
11571
  break;
11459
11572
  }
11460
11573
  case "upgrade": {
11461
- const { cmdUpgrade } = await import("./upgrade-VON7Y3LG.js");
11574
+ const { cmdUpgrade } = await import("./upgrade-7ZYWR2GH.js");
11462
11575
  const { flags } = parseLooseArgs(args);
11463
11576
  const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
11464
11577
  if (!workspaceInfo) break;
@@ -11470,10 +11583,10 @@ async function main() {
11470
11583
  case "heal": {
11471
11584
  if (command === "heal") {
11472
11585
  console.log(
11473
- `${YELLOW11}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11586
+ `${YELLOW12}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11474
11587
  );
11475
11588
  }
11476
- const { cmdHeal } = await import("./heal-ZQHEHBUJ.js");
11589
+ const { cmdHeal } = await import("./heal-2UCSPRTK.js");
11477
11590
  const { flags } = parseLooseArgs(args);
11478
11591
  const workspaceInfo = resolveWorkflowProject(flags, "check");
11479
11592
  if (!workspaceInfo) break;
@@ -11498,7 +11611,7 @@ async function main() {
11498
11611
  const { flags } = parseLooseArgs(args);
11499
11612
  const workspaceInfo = resolveWorkflowProject(flags, "health");
11500
11613
  if (!workspaceInfo) break;
11501
- const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
11614
+ const { cmdHealth, parseHealthArgs } = await import("./health-VAYRQVTF.js");
11502
11615
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
11503
11616
  } catch (e) {
11504
11617
  console.error(error2(e.message));
@@ -11526,7 +11639,7 @@ async function main() {
11526
11639
  cmdStudioHelp();
11527
11640
  break;
11528
11641
  }
11529
- const { cmdStudio, parseStudioArgs } = await import("./studio-2734P63C.js");
11642
+ const { cmdStudio, parseStudioArgs } = await import("./studio-WPETOZRW.js");
11530
11643
  await cmdStudio(process.cwd(), parseStudioArgs(args));
11531
11644
  } catch (e) {
11532
11645
  console.error(error2(e.message));
@@ -11540,7 +11653,7 @@ async function main() {
11540
11653
  cmdWorkspaceHelp();
11541
11654
  break;
11542
11655
  }
11543
- const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
11656
+ const { cmdWorkspace } = await import("./workspace-PBO3BJRL.js");
11544
11657
  await cmdWorkspace(process.cwd(), args);
11545
11658
  } catch (e) {
11546
11659
  console.error(error2(e.message));
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createProjectHealthReport,
3
3
  listWorkspaceAppCandidates
4
- } from "./chunk-FACL3NXU.js";
4
+ } from "./chunk-WPP3JEMC.js";
5
5
 
6
6
  // src/commands/workspace.ts
7
7
  import { execFileSync } from "child_process";
@@ -3,7 +3,7 @@ import {
3
3
  sendProjectHealthCiFailedTelemetry,
4
4
  sendProjectHealthPromptTelemetry,
5
5
  sendProjectHealthReportTelemetry
6
- } from "./chunk-WONPNSSI.js";
6
+ } from "./chunk-4SZ4SEKT.js";
7
7
 
8
8
  // src/commands/health.ts
9
9
  import { execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cmdHeal,
3
3
  collectCheckIssues
4
- } from "./chunk-WONPNSSI.js";
4
+ } from "./chunk-4SZ4SEKT.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-FACL3NXU.js";
14
- import "./chunk-WONPNSSI.js";
13
+ } from "./chunk-WPP3JEMC.js";
14
+ import "./chunk-4SZ4SEKT.js";
15
15
  export {
16
16
  cmdHealth,
17
17
  collectDesignTokenEvidence,
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./chunk-32H5SFKV.js";
2
- import "./chunk-RXF7ZYGK.js";
3
- import "./chunk-VCUFZB45.js";
4
- import "./chunk-FACL3NXU.js";
5
- import "./chunk-WONPNSSI.js";
1
+ import "./chunk-JSILTE5V.js";
2
+ import "./chunk-IQZCIMQJ.js";
3
+ import "./chunk-QDMXZSVK.js";
4
+ import "./chunk-WPP3JEMC.js";
5
+ import "./chunk-4SZ4SEKT.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createWorkspaceHealthReport
3
- } from "./chunk-VCUFZB45.js";
3
+ } from "./chunk-QDMXZSVK.js";
4
4
  import {
5
5
  createProjectHealthReport
6
- } from "./chunk-FACL3NXU.js";
6
+ } from "./chunk-WPP3JEMC.js";
7
7
  import {
8
8
  sendStudioHealthRefreshedTelemetry,
9
9
  sendStudioStartedTelemetry
10
- } from "./chunk-WONPNSSI.js";
10
+ } from "./chunk-4SZ4SEKT.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-RXF7ZYGK.js";
4
+ } from "./chunk-IQZCIMQJ.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-VCUFZB45.js";
11
- import "./chunk-FACL3NXU.js";
12
- import "./chunk-WONPNSSI.js";
10
+ } from "./chunk-QDMXZSVK.js";
11
+ import "./chunk-WPP3JEMC.js";
12
+ import "./chunk-4SZ4SEKT.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.6",
3
+ "version": "2.9.8",
4
4
  "description": "Decantr CLI - scaffold, audit, inspect Project Health, and maintain Decantr projects from the terminal",
5
5
  "keywords": [
6
6
  "decantr",
@@ -49,10 +49,10 @@
49
49
  "dependencies": {
50
50
  "ajv": "^8.20.0",
51
51
  "@decantr/core": "2.1.0",
52
- "@decantr/registry": "2.2.0",
53
- "@decantr/essence-spec": "2.0.1",
54
52
  "@decantr/verifier": "2.3.3",
55
- "@decantr/telemetry": "2.2.1"
53
+ "@decantr/telemetry": "2.2.1",
54
+ "@decantr/essence-spec": "2.0.1",
55
+ "@decantr/registry": "2.2.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",