@decantr/cli 2.9.2 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,14 +22,14 @@ import {
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
24
  shouldFailWorkspaceHealth
25
- } from "./chunk-R57DMFLF.js";
25
+ } from "./chunk-ARR3EPS2.js";
26
26
  import {
27
27
  createProjectHealthReport,
28
28
  formatProjectHealthMarkdown,
29
29
  formatProjectHealthText,
30
30
  resolveWorkspaceInfo,
31
31
  shouldFailHealth
32
- } from "./chunk-DX2UDORT.js";
32
+ } from "./chunk-XZFKK6V7.js";
33
33
  import {
34
34
  buildGuardRegistryContext,
35
35
  createDoctrineMap,
@@ -50,7 +50,7 @@ import {
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, join as join31, resolve as resolve4 } from "path";
53
+ import { basename as basename3, dirname as dirname5, 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 {
@@ -1772,6 +1772,20 @@ function readV4Essence(projectRoot) {
1772
1772
  function writeEssence(essencePath, essence) {
1773
1773
  writeFileSync6(essencePath, JSON.stringify(essence, null, 2) + "\n");
1774
1774
  }
1775
+ function readFlagValue(args, name) {
1776
+ const prefix = `--${name}=`;
1777
+ for (let index = 0; index < args.length; index += 1) {
1778
+ const arg = args[index];
1779
+ if (arg === `--${name}` && args[index + 1]) return args[index + 1];
1780
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
1781
+ }
1782
+ return void 0;
1783
+ }
1784
+ function normalizeRoute(route) {
1785
+ const trimmed = route.trim();
1786
+ if (!trimmed || trimmed === "/") return "/";
1787
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
1788
+ }
1775
1789
  async function cmdAddSection(archetypeId, args, projectRoot = process.cwd()) {
1776
1790
  if (!archetypeId) {
1777
1791
  console.error(`${RED}Usage: decantr add section <archetypeId>${RESET}`);
@@ -1847,12 +1861,27 @@ async function cmdAddPage(path, args, projectRoot = process.cwd()) {
1847
1861
  process.exitCode = 1;
1848
1862
  return;
1849
1863
  }
1864
+ const route = normalizeRoute(readFlagValue(args, "route") ?? pageId);
1865
+ const routes = essence.blueprint.routes ??= {};
1866
+ const existingRoute = routes[route];
1867
+ if (existingRoute) {
1868
+ console.error(
1869
+ `${RED}Route "${route}" already maps to ${existingRoute.section}/${existingRoute.page}.${RESET}`
1870
+ );
1871
+ console.error(`${DIM}Pass a unique route with --route /some-path.${RESET}`);
1872
+ process.exitCode = 1;
1873
+ return;
1874
+ }
1850
1875
  section.pages.push({
1851
1876
  id: pageId,
1877
+ route,
1852
1878
  layout: ["hero"]
1853
1879
  });
1880
+ routes[route] = { section: sectionId, page: pageId };
1854
1881
  writeEssence(essencePath, essence);
1855
- console.log(`${GREEN}Added page "${pageId}" to section "${sectionId}".${RESET}`);
1882
+ console.log(
1883
+ `${GREEN}Added page "${pageId}" to section "${sectionId}" at route "${route}".${RESET}`
1884
+ );
1856
1885
  const registryClient = new RegistryClient({
1857
1886
  cacheDir: join6(projectRoot, ".decantr", "cache")
1858
1887
  });
@@ -1869,10 +1898,7 @@ async function cmdAddFeature(feature, args, projectRoot = process.cwd()) {
1869
1898
  if (!loaded) return;
1870
1899
  const { essence, essencePath } = loaded;
1871
1900
  let sectionId;
1872
- const sectionIdx = args.indexOf("--section");
1873
- if (sectionIdx !== -1 && args[sectionIdx + 1]) {
1874
- sectionId = args[sectionIdx + 1];
1875
- }
1901
+ sectionId = readFlagValue(args, "section");
1876
1902
  if (sectionId) {
1877
1903
  const sections = essence.blueprint.sections;
1878
1904
  const section = sections.find((s) => s.id === sectionId);
@@ -1901,7 +1927,7 @@ async function cmdAddFeature(feature, args, projectRoot = process.cwd()) {
1901
1927
 
1902
1928
  // src/commands/analyze.ts
1903
1929
  import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
1904
- import { join as join14 } from "path";
1930
+ import { join as join14, relative as relative2 } from "path";
1905
1931
 
1906
1932
  // src/analyzers/components.ts
1907
1933
  import { existsSync as existsSync5, readdirSync, statSync as statSync2 } from "fs";
@@ -2957,6 +2983,10 @@ ${BOLD}Analyzing project...${RESET2}
2957
2983
  const doctrine = createDoctrineMap(ambient);
2958
2984
  const initSeed = createBrownfieldInitSeed(project, layout, styling);
2959
2985
  initSeed.projectScope = workspace?.projectScope ?? "single-app";
2986
+ const projectLabel = workspace && workspace.appRoot !== workspace.workspaceRoot ? relative2(workspace.workspaceRoot, workspace.appRoot).replace(/\\/g, "/") : null;
2987
+ const projectFlag = projectLabel ? ` --project ${projectLabel}` : "";
2988
+ const reportDisplayPath = projectLabel ? `${projectLabel}/.decantr/brownfield-report.md` : ".decantr/brownfield-report.md";
2989
+ const recommendedAttachCommand = `decantr init${projectFlag} --existing --accept-proposal`;
2960
2990
  const proposal = createBrownfieldProposal({
2961
2991
  project,
2962
2992
  routes,
@@ -2996,7 +3026,7 @@ ${BOLD}Analyzing project...${RESET2}
2996
3026
  adoptionMode: "contract-only",
2997
3027
  initSeedPath: ".decantr/init-seed.json",
2998
3028
  proposalPath: ".decantr/observed-essence.proposal.json",
2999
- recommendedCommand: "decantr init --existing --accept-proposal"
3029
+ recommendedCommand: recommendedAttachCommand
3000
3030
  },
3001
3031
  hybrid: {
3002
3032
  ownerCommands: [
@@ -3096,7 +3126,7 @@ ${DIM2}Written to:${RESET2} ${outputPath}`);
3096
3126
  console.log(`${DIM2}Enrichment backlog:${RESET2} ${intelligenceArtifacts.backlogPath}`);
3097
3127
  console.log(
3098
3128
  `
3099
- ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2}, then run ${BOLD}decantr init --existing --accept-proposal${RESET2} to attach Decantr using the observed proposal.
3129
+ ${YELLOW}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then run ${BOLD}${recommendedAttachCommand}${RESET2} to attach Decantr using the observed proposal.
3100
3130
  `
3101
3131
  );
3102
3132
  await sendAnalyzeCompletedTelemetry({
@@ -3119,12 +3149,12 @@ ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2
3119
3149
 
3120
3150
  // src/commands/ci.ts
3121
3151
  import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
3122
- import { dirname as dirname2, join as join16, relative as relative3, resolve } from "path";
3152
+ import { dirname as dirname2, join as join16, relative as relative4, resolve } from "path";
3123
3153
 
3124
3154
  // src/local-law.ts
3125
3155
  import { execFileSync } from "child_process";
3126
3156
  import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync5, writeFileSync as writeFileSync9 } from "fs";
3127
- import { basename as basename2, extname, join as join15, relative as relative2, sep } from "path";
3157
+ import { basename as basename2, extname, join as join15, relative as relative3, sep } from "path";
3128
3158
  import { isV4 as isV43 } from "@decantr/essence-spec";
3129
3159
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
3130
3160
  ".astro",
@@ -3565,7 +3595,7 @@ function listSourceFiles(projectRoot, maxFiles) {
3565
3595
  if (stat.isDirectory()) {
3566
3596
  visit(absolute);
3567
3597
  } else if (stat.isFile() && SOURCE_EXTENSIONS.has(extname(entry))) {
3568
- files.push({ absolute, relative: normalizePath(relative2(projectRoot, absolute)) });
3598
+ files.push({ absolute, relative: normalizePath(relative3(projectRoot, absolute)) });
3569
3599
  }
3570
3600
  }
3571
3601
  };
@@ -3653,7 +3683,8 @@ function parseCiArgs(args) {
3653
3683
  return options;
3654
3684
  }
3655
3685
  function parseProvider(value) {
3656
- return value === "generic" ? "generic" : "github";
3686
+ if (value === "github" || value === "generic") return value;
3687
+ throw new Error("Invalid --provider value. Use github or generic.");
3657
3688
  }
3658
3689
  function detectPackageManager(root) {
3659
3690
  const pkg = readJson(join16(root, "package.json"));
@@ -3843,6 +3874,9 @@ jobs:
3843
3874
  }
3844
3875
  function writeCiInit(root, options) {
3845
3876
  const workspaceInfo = resolveWorkspaceInfo(root, options.project);
3877
+ if (options.project && !existsSync14(workspaceInfo.appRoot)) {
3878
+ throw new Error(`Project path does not exist: ${options.project}`);
3879
+ }
3846
3880
  if (workspaceInfo.requiresProjectSelection && !options.workspace) {
3847
3881
  const candidate = workspaceInfo.appCandidates[0] ?? "apps/web";
3848
3882
  throw new Error(
@@ -3850,7 +3884,7 @@ function writeCiInit(root, options) {
3850
3884
  );
3851
3885
  }
3852
3886
  const outputRoot = workspaceInfo.workspaceRoot;
3853
- const projectPath = options.project ?? (options.workspace || workspaceInfo.appRoot === workspaceInfo.workspaceRoot ? void 0 : relative3(workspaceInfo.workspaceRoot, workspaceInfo.appRoot).replace(/\\/g, "/"));
3887
+ const projectPath = options.project ?? (options.workspace || workspaceInfo.appRoot === workspaceInfo.workspaceRoot ? void 0 : relative4(workspaceInfo.workspaceRoot, workspaceInfo.appRoot).replace(/\\/g, "/"));
3854
3888
  const packageManager = detectPackageManager(outputRoot);
3855
3889
  const command = decantrCommand(packageManager);
3856
3890
  const failOn = options.failOn ?? "error";
@@ -3933,6 +3967,10 @@ async function runWorkspaceCi(root, options) {
3933
3967
  }
3934
3968
  async function runProjectCi(root, options) {
3935
3969
  const workspaceInfo = resolveWorkspaceInfo(root, options.project);
3970
+ if (options.project && !existsSync14(workspaceInfo.appRoot)) {
3971
+ console.error(`${RED2}Project path does not exist: ${options.project}${RESET3}`);
3972
+ return 1;
3973
+ }
3936
3974
  if (workspaceInfo.requiresProjectSelection) {
3937
3975
  const candidate = workspaceInfo.appCandidates[0] ?? "apps/web";
3938
3976
  console.error(`${RED2}Decantr CI needs an app path in this monorepo.${RESET3}`);
@@ -3983,16 +4021,16 @@ ${BOLD2}Examples:${RESET3}
3983
4021
  `);
3984
4022
  }
3985
4023
  async function cmdCi(args = ["ci"], root = process.cwd()) {
3986
- const options = parseCiArgs(args);
3987
4024
  try {
4025
+ const options = parseCiArgs(args);
3988
4026
  if (options.init) {
3989
4027
  writeCiInit(root, options);
3990
4028
  return;
3991
4029
  }
3992
4030
  const exitCode = options.workspace ? await runWorkspaceCi(root, options) : await runProjectCi(root, options);
3993
4031
  if (exitCode !== 0) process.exitCode = exitCode;
3994
- } catch (error4) {
3995
- console.error(`${RED2}${error4.message}${RESET3}`);
4032
+ } catch (error3) {
4033
+ console.error(`${RED2}${error3.message}${RESET3}`);
3996
4034
  process.exitCode = 1;
3997
4035
  }
3998
4036
  }
@@ -4211,7 +4249,7 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
4211
4249
 
4212
4250
  // src/commands/doctor.ts
4213
4251
  import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
4214
- import { dirname as dirname3, join as join18, relative as relative4 } from "path";
4252
+ import { dirname as dirname3, join as join18, relative as relative5 } from "path";
4215
4253
  import { fileURLToPath } from "url";
4216
4254
  import { isV4 as isV44 } from "@decantr/essence-spec";
4217
4255
  import { collectMissingPackManifestFiles } from "@decantr/verifier";
@@ -4230,6 +4268,10 @@ function readJson2(path) {
4230
4268
  return null;
4231
4269
  }
4232
4270
  }
4271
+ function isContractOnlyProject(projectRoot) {
4272
+ const projectJson = readJson2(join18(projectRoot, ".decantr", "project.json"));
4273
+ return projectJson?.initialized?.adoptionMode === "contract-only";
4274
+ }
4233
4275
  function readCliPackageVersion() {
4234
4276
  const packagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4235
4277
  const srcPackagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "package.json");
@@ -4255,8 +4297,28 @@ function localCliDependency(root) {
4255
4297
  const pkg = readPackageJson(root);
4256
4298
  return pkg?.devDependencies?.["@decantr/cli"] ?? pkg?.dependencies?.["@decantr/cli"] ?? null;
4257
4299
  }
4300
+ function hasWorkspaceMarker2(root) {
4301
+ const pkg = readPackageJson(root);
4302
+ return Boolean(
4303
+ existsSync16(join18(root, "pnpm-workspace.yaml")) || existsSync16(join18(root, "turbo.json")) || existsSync16(join18(root, "nx.json")) || pkg?.workspaces
4304
+ );
4305
+ }
4306
+ function pinCliCommand2(packageManager, root) {
4307
+ switch (packageManager) {
4308
+ case "pnpm":
4309
+ return hasWorkspaceMarker2(root) ? "pnpm add -D -w @decantr/cli" : "pnpm add -D @decantr/cli";
4310
+ case "yarn":
4311
+ return "yarn add -D @decantr/cli";
4312
+ case "bun":
4313
+ return "bun add -d @decantr/cli";
4314
+ case "npm":
4315
+ return "npm install -D @decantr/cli";
4316
+ default:
4317
+ return "npm install -D @decantr/cli";
4318
+ }
4319
+ }
4258
4320
  function rel(root, path) {
4259
- const value = relative4(root, path).replace(/\\/g, "/");
4321
+ const value = relative5(root, path).replace(/\\/g, "/");
4260
4322
  return value || ".";
4261
4323
  }
4262
4324
  function hasAnyFile(dir, names) {
@@ -4335,14 +4397,20 @@ function statusFromIssues(issues, essenceVersion) {
4335
4397
  return "healthy";
4336
4398
  }
4337
4399
  function buildDoctorReport(root, args) {
4338
- const projectIdx = args.indexOf("--project");
4339
- const projectArg = projectIdx !== -1 && args[projectIdx + 1] ? args[projectIdx + 1] : void 0;
4400
+ let projectArg;
4401
+ for (let index = 1; index < args.length; index += 1) {
4402
+ const arg = args[index];
4403
+ if (arg === "--project" && args[index + 1]) projectArg = args[++index];
4404
+ else if (arg.startsWith("--project=")) projectArg = arg.slice("--project=".length);
4405
+ }
4340
4406
  const workspaceMode = args.includes("--workspace");
4341
4407
  const workspaceInfo = resolveWorkspaceInfo(root, projectArg);
4342
4408
  const workspaceRoot = workspaceInfo.workspaceRoot;
4343
4409
  const appRoot = workspaceMode ? workspaceRoot : workspaceInfo.appRoot;
4410
+ const projectMissing = Boolean(projectArg && !existsSync16(appRoot));
4344
4411
  const projectPath = appRoot === workspaceRoot ? null : rel(workspaceRoot, appRoot);
4345
4412
  const packageManager = detectPackageManager2(workspaceRoot);
4413
+ const cliDependency = localCliDependency(workspaceRoot);
4346
4414
  const detected = detectProject(appRoot);
4347
4415
  const projectJson = readJson2(join18(appRoot, ".decantr", "project.json"));
4348
4416
  const essence = readJson2(join18(appRoot, "decantr.essence.json"));
@@ -4360,6 +4428,7 @@ function buildDoctorReport(root, args) {
4360
4428
  const ciFiles = findCiFiles(workspaceRoot);
4361
4429
  const workflowMode = projectJson?.initialized?.workflowMode ?? null;
4362
4430
  const adoptionMode = projectJson?.initialized?.adoptionMode ?? null;
4431
+ const packHydrationOptional = adoptionMode === "contract-only";
4363
4432
  const missingPackReferences = workspaceMode ? projects.flatMap(
4364
4433
  (project) => collectMissingPackManifestFiles(join18(workspaceRoot, project.path)).map(
4365
4434
  (missing) => `${project.path}/${missing.relativePath}`
@@ -4367,14 +4436,21 @@ function buildDoctorReport(root, args) {
4367
4436
  ) : collectMissingPackManifestFiles(appRoot).map((missing) => missing.relativePath);
4368
4437
  const workspaceProjectsMissingManifest = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
4369
4438
  const projectContextDir = join18(workspaceRoot, projectPath2, ".decantr", "context");
4370
- return !existsSync16(join18(projectContextDir, "pack-manifest.json"));
4439
+ return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "pack-manifest.json"));
4371
4440
  }) : [];
4372
4441
  const workspaceProjectsMissingReviewPack = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
4373
4442
  const projectContextDir = join18(workspaceRoot, projectPath2, ".decantr", "context");
4374
- return !existsSync16(join18(projectContextDir, "review-pack.json"));
4443
+ return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "review-pack.json"));
4375
4444
  }) : [];
4376
4445
  const issues = [];
4377
- if (!essenceVersion && !workspaceMode && !workspaceInfo.requiresProjectSelection) {
4446
+ if (projectMissing) {
4447
+ issues.push({
4448
+ category: "workspace",
4449
+ severity: "error",
4450
+ message: `Project path does not exist: ${projectArg}`,
4451
+ nextCommand: "decantr workspace list"
4452
+ });
4453
+ } else if (!essenceVersion && !workspaceMode && !workspaceInfo.requiresProjectSelection) {
4378
4454
  issues.push({
4379
4455
  category: "setup",
4380
4456
  severity: "error",
@@ -4405,6 +4481,14 @@ function buildDoctorReport(root, args) {
4405
4481
  nextCommand: "decantr setup"
4406
4482
  });
4407
4483
  }
4484
+ if ((essenceVersion === "4.0.0" || workspaceMode || projects.length > 0) && !cliDependency) {
4485
+ issues.push({
4486
+ category: "ci",
4487
+ severity: "info",
4488
+ message: "@decantr/cli is not pinned in the workspace root package.json.",
4489
+ nextCommand: pinCliCommand2(packageManager, workspaceRoot)
4490
+ });
4491
+ }
4408
4492
  if (essenceVersion === "4.0.0" && !artifactReadmePresent) {
4409
4493
  issues.push({
4410
4494
  category: "generated-artifact",
@@ -4413,7 +4497,7 @@ function buildDoctorReport(root, args) {
4413
4497
  nextCommand: "decantr refresh"
4414
4498
  });
4415
4499
  }
4416
- if (essenceVersion === "4.0.0" && (!existsSync16(contextDir) || !packManifestPresent)) {
4500
+ if (essenceVersion === "4.0.0" && !packHydrationOptional && (!existsSync16(contextDir) || !packManifestPresent)) {
4417
4501
  issues.push({
4418
4502
  category: "generated-artifact",
4419
4503
  severity: "warn",
@@ -4473,7 +4557,7 @@ function buildDoctorReport(root, args) {
4473
4557
  projectPath,
4474
4558
  packageManager,
4475
4559
  cli: {
4476
- localDependency: localCliDependency(workspaceRoot),
4560
+ localDependency: cliDependency,
4477
4561
  runningVersion: readCliPackageVersion()
4478
4562
  },
4479
4563
  project: {
@@ -4584,18 +4668,24 @@ async function cmdDoctor(args = ["doctor"], root = process.cwd()) {
4584
4668
  const report = buildDoctorReport(root, args);
4585
4669
  if (args.includes("--json")) {
4586
4670
  console.log(JSON.stringify(report, null, 2));
4671
+ if (report.issues.some((issue) => issue.severity === "error")) process.exitCode = 1;
4587
4672
  return;
4588
4673
  }
4589
4674
  process.stdout.write(formatDoctorText(report));
4675
+ if (report.issues.some((issue) => issue.severity === "error")) process.exitCode = 1;
4590
4676
  }
4591
4677
 
4592
4678
  // src/commands/export.ts
4593
4679
  import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
4594
- import { dirname as dirname4, join as join19 } from "path";
4680
+ import { dirname as dirname4, isAbsolute, join as join19 } from "path";
4595
4681
  var GREEN5 = "\x1B[32m";
4596
4682
  var RED4 = "\x1B[31m";
4597
4683
  var DIM5 = "\x1B[2m";
4598
4684
  var RESET5 = "\x1B[0m";
4685
+ function resolveOutputPath(projectRoot, output, fallback) {
4686
+ if (!output) return fallback;
4687
+ return isAbsolute(output) ? output : join19(projectRoot, output);
4688
+ }
4599
4689
  var SHADCN_MAP = {
4600
4690
  "--d-bg": "--background",
4601
4691
  "--d-text": "--foreground",
@@ -4744,9 +4834,7 @@ function generateFigmaTokens(tokens) {
4744
4834
  const out = {};
4745
4835
  for (const [key, value] of tokens) {
4746
4836
  const name = key.replace(/^--/, "").replace(/-/g, ".");
4747
- const type = /color|bg|surface|text|border|primary|secondary|accent|error|warning|success|info/.test(
4748
- key
4749
- ) ? "color" : /radius/.test(key) ? "borderRadius" : /shadow/.test(key) ? "shadow" : /gap|space|spacing/.test(key) ? "dimension" : "string";
4837
+ const type = /color|bg|surface|text|border|primary|secondary|accent|error|warning|success|info/.test(key) ? "color" : /radius/.test(key) ? "borderRadius" : /shadow/.test(key) ? "shadow" : /gap|space|spacing/.test(key) ? "dimension" : "string";
4750
4838
  out[name] = {
4751
4839
  $type: type,
4752
4840
  $value: value,
@@ -4780,7 +4868,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4780
4868
  }
4781
4869
  switch (target) {
4782
4870
  case "shadcn": {
4783
- const cssOut = options.output ?? join19(projectRoot, "src", "styles", "shadcn-theme.css");
4871
+ const cssOut = resolveOutputPath(
4872
+ projectRoot,
4873
+ options.output,
4874
+ join19(projectRoot, "src", "styles", "shadcn-theme.css")
4875
+ );
4784
4876
  const jsonOut = join19(projectRoot, "components.json");
4785
4877
  ensureDir(cssOut);
4786
4878
  writeFileSync12(cssOut, generateShadcnCSS(tokens), "utf-8");
@@ -4791,7 +4883,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4791
4883
  break;
4792
4884
  }
4793
4885
  case "tailwind": {
4794
- const out = options.output ?? join19(projectRoot, "tailwind.decantr.config.ts");
4886
+ const out = resolveOutputPath(
4887
+ projectRoot,
4888
+ options.output,
4889
+ join19(projectRoot, "tailwind.decantr.config.ts")
4890
+ );
4795
4891
  ensureDir(out);
4796
4892
  writeFileSync12(out, generateTailwindConfig(tokens), "utf-8");
4797
4893
  console.log(`${GREEN5}Exported Tailwind config:${RESET5}`);
@@ -4799,7 +4895,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4799
4895
  break;
4800
4896
  }
4801
4897
  case "css-vars": {
4802
- const out = options.output ?? join19(projectRoot, "decantr-tokens.css");
4898
+ const out = resolveOutputPath(
4899
+ projectRoot,
4900
+ options.output,
4901
+ join19(projectRoot, "decantr-tokens.css")
4902
+ );
4803
4903
  ensureDir(out);
4804
4904
  writeFileSync12(out, generateCSSVars(tokens), "utf-8");
4805
4905
  console.log(`${GREEN5}Exported CSS variables:${RESET5}`);
@@ -4807,7 +4907,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4807
4907
  break;
4808
4908
  }
4809
4909
  case "figma-tokens": {
4810
- const out = options.output ?? join19(projectRoot, ".decantr", "design", "figma-tokens.json");
4910
+ const out = resolveOutputPath(
4911
+ projectRoot,
4912
+ options.output,
4913
+ join19(projectRoot, ".decantr", "design", "figma-tokens.json")
4914
+ );
4811
4915
  ensureDir(out);
4812
4916
  writeFileSync12(out, generateFigmaTokens(tokens), "utf-8");
4813
4917
  console.log(`${GREEN5}Exported Figma/Tokens Studio tokens:${RESET5}`);
@@ -4830,7 +4934,6 @@ import { join as join20 } from "path";
4830
4934
  var BOLD4 = "\x1B[1m";
4831
4935
  var DIM6 = "\x1B[2m";
4832
4936
  var RESET6 = "\x1B[0m";
4833
- var RED5 = "\x1B[31m";
4834
4937
  var GREEN6 = "\x1B[32m";
4835
4938
  var CYAN3 = "\x1B[36m";
4836
4939
  var YELLOW3 = "\x1B[33m";
@@ -4838,9 +4941,6 @@ var MAGENTA = "\x1B[35m";
4838
4941
  function success(text) {
4839
4942
  return `${GREEN6}${text}${RESET6}`;
4840
4943
  }
4841
- function error(text) {
4842
- return `${RED5}${text}${RESET6}`;
4843
- }
4844
4944
  function dim(text) {
4845
4945
  return `${DIM6}${text}${RESET6}`;
4846
4946
  }
@@ -5056,9 +5156,16 @@ async function cmdMagic(prompt, projectRoot, options) {
5056
5156
  console.log("");
5057
5157
  const essencePath = join20(projectRoot, "decantr.essence.json");
5058
5158
  if (existsSync18(essencePath)) {
5059
- console.log(error(" decantr.essence.json already exists in this directory."));
5060
- console.log(dim(" Remove it first or use a different directory."));
5061
- process.exitCode = 1;
5159
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5160
+ console.log(`${YELLOW3} Decantr is already attached to this project.${RESET6}`);
5161
+ console.log(
5162
+ dim(" decantr magic is greenfield-first; use task-time context for existing apps.")
5163
+ );
5164
+ console.log("");
5165
+ console.log(`${BOLD4}Recommended next steps:${RESET6}`);
5166
+ console.log(` ${cyan(`decantr doctor${projectFlag}`)}`);
5167
+ console.log(` ${cyan(`decantr task <route> "${prompt}"${projectFlag}`)}`);
5168
+ console.log(` ${cyan(`decantr verify --brownfield --local-patterns${projectFlag}`)}`);
5062
5169
  return;
5063
5170
  }
5064
5171
  const detected = detectProject(projectRoot);
@@ -5073,8 +5180,9 @@ async function cmdMagic(prompt, projectRoot, options) {
5073
5180
  dim(" Running brownfield analysis instead so you can attach Decantr deliberately.\n")
5074
5181
  );
5075
5182
  await cmdAnalyze(projectRoot);
5183
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5076
5184
  console.log(
5077
- `${BOLD4}Recommended next step:${RESET6} ${cyan("decantr init --existing --accept-proposal")}`
5185
+ `${BOLD4}Recommended next step:${RESET6} ${cyan(`decantr init${projectFlag} --existing --accept-proposal`)}`
5078
5186
  );
5079
5187
  console.log("");
5080
5188
  return;
@@ -5400,7 +5508,7 @@ import {
5400
5508
  validateLegacyEssenceForMigration
5401
5509
  } from "@decantr/essence-spec";
5402
5510
  var GREEN7 = "\x1B[32m";
5403
- var RED6 = "\x1B[31m";
5511
+ var RED5 = "\x1B[31m";
5404
5512
  var YELLOW4 = "\x1B[33m";
5405
5513
  var RESET7 = "\x1B[0m";
5406
5514
  var DIM7 = "\x1B[2m";
@@ -5468,13 +5576,13 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5468
5576
  const inlineTarget = hasInlineTarget?.split("=")[1];
5469
5577
  const requestedTarget = inlineTarget ?? target;
5470
5578
  if (requestedTarget !== "v4") {
5471
- console.error(`${RED6}Usage: decantr migrate --to v4${RESET7}`);
5579
+ console.error(`${RED5}Usage: decantr migrate --to v4${RESET7}`);
5472
5580
  process.exitCode = 1;
5473
5581
  return;
5474
5582
  }
5475
5583
  const essencePath = join21(projectRoot, "decantr.essence.json");
5476
5584
  if (!existsSync19(essencePath)) {
5477
- console.error(`${RED6}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5585
+ console.error(`${RED5}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5478
5586
  process.exitCode = 1;
5479
5587
  return;
5480
5588
  }
@@ -5485,7 +5593,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5485
5593
  return;
5486
5594
  }
5487
5595
  if (!result.success) {
5488
- console.error(`${RED6}Migration failed: ${result.error}${RESET7}`);
5596
+ console.error(`${RED5}Migration failed: ${result.error}${RESET7}`);
5489
5597
  process.exitCode = 1;
5490
5598
  return;
5491
5599
  }
@@ -5565,7 +5673,7 @@ function seedOfflineRegistry(projectDir, workspaceRoot) {
5565
5673
  var BOLD5 = "\x1B[1m";
5566
5674
  var DIM8 = "\x1B[2m";
5567
5675
  var RESET8 = "\x1B[0m";
5568
- var RED7 = "\x1B[31m";
5676
+ var RED6 = "\x1B[31m";
5569
5677
  var GREEN8 = "\x1B[32m";
5570
5678
  var CYAN4 = "\x1B[36m";
5571
5679
  var YELLOW5 = "\x1B[33m";
@@ -5577,8 +5685,8 @@ ${BOLD5}${text}${RESET8}
5577
5685
  function success2(text) {
5578
5686
  return `${GREEN8}${text}${RESET8}`;
5579
5687
  }
5580
- function error2(text) {
5581
- return `${RED7}${text}${RESET8}`;
5688
+ function error(text) {
5689
+ return `${RED6}${text}${RESET8}`;
5582
5690
  }
5583
5691
  function dim2(text) {
5584
5692
  return `${DIM8}${text}${RESET8}`;
@@ -5685,13 +5793,13 @@ async function cmdNewProject(projectName, options) {
5685
5793
  const shouldBootstrapRuntime = Boolean(bootstrapAdapter && inferredAdoption === "decantr-css");
5686
5794
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
5687
5795
  console.error(
5688
- error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5796
+ error("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5689
5797
  );
5690
5798
  process.exitCode = 1;
5691
5799
  return;
5692
5800
  }
5693
5801
  if (existsSync21(projectDir)) {
5694
- console.error(error2(`Directory "${projectName}" already exists.`));
5802
+ console.error(error(`Directory "${projectName}" already exists.`));
5695
5803
  process.exitCode = 1;
5696
5804
  return;
5697
5805
  }
@@ -5699,7 +5807,7 @@ async function cmdNewProject(projectName, options) {
5699
5807
  try {
5700
5808
  initFlags = buildNewProjectInitArgs(options, inferredAdoption);
5701
5809
  } catch (err) {
5702
- console.error(error2(err.message));
5810
+ console.error(error(err.message));
5703
5811
  process.exitCode = 1;
5704
5812
  return;
5705
5813
  }
@@ -5882,11 +5990,11 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
5882
5990
  // src/commands/refresh.ts
5883
5991
  import { createHash } from "crypto";
5884
5992
  import { existsSync as existsSync23, readdirSync as readdirSync7, readFileSync as readFileSync17, statSync as statSync6 } from "fs";
5885
- import { join as join25 } from "path";
5993
+ import { isAbsolute as isAbsolute2, join as join25, relative as relative6 } from "path";
5886
5994
  import { collectMissingPackManifestFiles as collectMissingPackManifestFiles2 } from "@decantr/verifier";
5887
5995
  import { isV4 as isV46 } from "@decantr/essence-spec";
5888
5996
  var GREEN9 = "\x1B[32m";
5889
- var RED8 = "\x1B[31m";
5997
+ var RED7 = "\x1B[31m";
5890
5998
  var DIM9 = "\x1B[2m";
5891
5999
  var RESET9 = "\x1B[0m";
5892
6000
  function hashFile(path) {
@@ -5937,18 +6045,29 @@ function newestInputMtime(projectRoot) {
5937
6045
  fileMtimeMs(join25(projectRoot, ".decantr", "project.json"))
5938
6046
  );
5939
6047
  }
6048
+ function isContractOnlyProject2(projectRoot) {
6049
+ const projectJsonPath = join25(projectRoot, ".decantr", "project.json");
6050
+ if (!existsSync23(projectJsonPath)) return false;
6051
+ try {
6052
+ const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
6053
+ return projectJson.initialized?.adoptionMode === "contract-only";
6054
+ } catch {
6055
+ return false;
6056
+ }
6057
+ }
5940
6058
  function checkRefreshFreshness(projectRoot) {
5941
6059
  const contextDir = join25(projectRoot, ".decantr", "context");
5942
6060
  const generated = trackedGeneratedFiles(projectRoot);
5943
6061
  const reasons = [];
6062
+ const packHydrationOptional = isContractOnlyProject2(projectRoot);
5944
6063
  if (!existsSync23(join25(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
5945
6064
  if (!existsSync23(contextDir)) reasons.push(".decantr/context is missing.");
5946
6065
  if (!existsSync23(join25(contextDir, "scaffold.md"))) {
5947
6066
  reasons.push(".decantr/context/scaffold.md is missing.");
5948
6067
  }
5949
- if (!existsSync23(join25(contextDir, "pack-manifest.json"))) {
6068
+ if (!packHydrationOptional && !existsSync23(join25(contextDir, "pack-manifest.json"))) {
5950
6069
  reasons.push(".decantr/context/pack-manifest.json is missing.");
5951
- } else {
6070
+ } else if (existsSync23(join25(contextDir, "pack-manifest.json"))) {
5952
6071
  const missingPackFiles = collectMissingPackManifestFiles2(projectRoot);
5953
6072
  if (missingPackFiles.length > 0) {
5954
6073
  reasons.push(
@@ -5999,10 +6118,19 @@ function summarizeChanges(projectRoot, before, after) {
5999
6118
  unchanged: unchanged.sort()
6000
6119
  };
6001
6120
  }
6002
- function printRefreshSummary(summary) {
6121
+ function displayGeneratedPath(summary, file, displayRoot) {
6122
+ if (!displayRoot) return file;
6123
+ const absolutePath = join25(summary.projectRoot, file);
6124
+ const relativePath = relative6(displayRoot, absolutePath).replace(/\\/g, "/");
6125
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute2(relativePath)) {
6126
+ return relativePath;
6127
+ }
6128
+ return absolutePath;
6129
+ }
6130
+ function printRefreshSummary(summary, displayRoot) {
6003
6131
  if (summary.check) {
6004
6132
  if (summary.stale) {
6005
- console.log(`${RED8}Generated Decantr context is stale.${RESET9}`);
6133
+ console.log(`${RED7}Generated Decantr context is stale.${RESET9}`);
6006
6134
  for (const reason of summary.reasons) console.log(` ${reason}`);
6007
6135
  console.log(`${DIM9}Run \`decantr refresh\` to regenerate derived files.${RESET9}`);
6008
6136
  } else {
@@ -6018,7 +6146,9 @@ function printRefreshSummary(summary) {
6018
6146
  for (const [label, files] of groups) {
6019
6147
  if (files.length === 0) continue;
6020
6148
  console.log(`${GREEN9}${label}:${RESET9}`);
6021
- for (const file of files) console.log(` ${DIM9}${file}${RESET9}`);
6149
+ for (const file of files) {
6150
+ console.log(` ${DIM9}${displayGeneratedPath(summary, file, displayRoot)}${RESET9}`);
6151
+ }
6022
6152
  }
6023
6153
  if (groups.every(([, files]) => files.length === 0)) {
6024
6154
  console.log(`${GREEN9}Generated files were already current.${RESET9}`);
@@ -6027,7 +6157,7 @@ function printRefreshSummary(summary) {
6027
6157
  async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6028
6158
  const essencePath = join25(projectRoot, "decantr.essence.json");
6029
6159
  if (!existsSync23(essencePath)) {
6030
- console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6160
+ console.error(`${RED7}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6031
6161
  process.exitCode = 1;
6032
6162
  return;
6033
6163
  }
@@ -6037,14 +6167,14 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6037
6167
  const parsed = JSON.parse(raw);
6038
6168
  if (!isV46(parsed)) {
6039
6169
  console.error(
6040
- `${RED8}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6170
+ `${RED7}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6041
6171
  );
6042
6172
  process.exitCode = 1;
6043
6173
  return;
6044
6174
  }
6045
6175
  essence = parsed;
6046
6176
  } catch (e) {
6047
- console.error(`${RED8}Could not read essence: ${e.message}${RESET9}`);
6177
+ console.error(`${RED7}Could not read essence: ${e.message}${RESET9}`);
6048
6178
  process.exitCode = 1;
6049
6179
  return;
6050
6180
  }
@@ -6053,7 +6183,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6053
6183
  if (options.json) {
6054
6184
  console.log(JSON.stringify(summary2, null, 2));
6055
6185
  } else {
6056
- printRefreshSummary(summary2);
6186
+ printRefreshSummary(summary2, options.displayRoot);
6057
6187
  }
6058
6188
  if (summary2.stale) process.exitCode = 1;
6059
6189
  return;
@@ -6070,17 +6200,19 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6070
6200
  if (options.json) {
6071
6201
  console.log(JSON.stringify({ ...summary, result }, null, 2));
6072
6202
  } else if (options.listChanges) {
6073
- printRefreshSummary(summary);
6203
+ printRefreshSummary(summary, options.displayRoot);
6074
6204
  } else {
6075
6205
  console.log(`${GREEN9}Regenerated:${RESET9}`);
6076
- console.log(` ${DIM9}DECANTR.md${RESET9}`);
6206
+ console.log(
6207
+ ` ${DIM9}${displayGeneratedPath(summary, "DECANTR.md", options.displayRoot)}${RESET9}`
6208
+ );
6077
6209
  for (const css of result.cssFiles) {
6078
6210
  const rel2 = css.replace(projectRoot + "/", "");
6079
- console.log(` ${DIM9}${rel2}${RESET9}`);
6211
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6080
6212
  }
6081
6213
  for (const ctx of result.contextFiles) {
6082
6214
  const rel2 = ctx.replace(projectRoot + "/", "");
6083
- console.log(` ${DIM9}${rel2}${RESET9}`);
6215
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6084
6216
  }
6085
6217
  }
6086
6218
  console.log("");
@@ -6092,7 +6224,7 @@ import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync14 } from "fs";
6092
6224
  import { join as join26 } from "path";
6093
6225
  import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
6094
6226
  var GREEN10 = "\x1B[32m";
6095
- var RED9 = "\x1B[31m";
6227
+ var RED8 = "\x1B[31m";
6096
6228
  var DIM10 = "\x1B[2m";
6097
6229
  var CYAN5 = "\x1B[36m";
6098
6230
  var YELLOW6 = "\x1B[33m";
@@ -6106,13 +6238,13 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
6106
6238
  });
6107
6239
  const healthy = await apiClient.checkHealth();
6108
6240
  if (!healthy) {
6109
- console.error(`${RED9}Registry API is unavailable. Check your connection.${RESET10}`);
6241
+ console.error(`${RED8}Registry API is unavailable. Check your connection.${RESET10}`);
6110
6242
  process.exitCode = 1;
6111
6243
  return;
6112
6244
  }
6113
6245
  const types = options.type ? [options.type] : ALL_CONTENT_TYPES;
6114
6246
  if (options.type && !ALL_CONTENT_TYPES.includes(options.type)) {
6115
- console.error(`${RED9}Unknown content type: ${options.type}${RESET10}`);
6247
+ console.error(`${RED8}Unknown content type: ${options.type}${RESET10}`);
6116
6248
  console.error(`${DIM10}Valid types: ${ALL_CONTENT_TYPES.join(", ")}${RESET10}`);
6117
6249
  process.exitCode = 1;
6118
6250
  return;
@@ -6147,7 +6279,7 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6147
6279
  console.log(` ${GREEN10}\u2713${RESET10} ${type}: ${CYAN5}${itemCount}${RESET10} items`);
6148
6280
  } catch (e) {
6149
6281
  failed.push(type);
6150
- console.log(` ${RED9}\u2717${RESET10} ${type}: ${e.message}`);
6282
+ console.log(` ${RED8}\u2717${RESET10} ${type}: ${e.message}`);
6151
6283
  }
6152
6284
  }
6153
6285
  const manifest = {
@@ -6176,13 +6308,13 @@ import { existsSync as existsSync25, readFileSync as readFileSync18, rmSync as r
6176
6308
  import { join as join27 } from "path";
6177
6309
  import { isV4 as isV47 } from "@decantr/essence-spec";
6178
6310
  var GREEN11 = "\x1B[32m";
6179
- var RED10 = "\x1B[31m";
6311
+ var RED9 = "\x1B[31m";
6180
6312
  var DIM11 = "\x1B[2m";
6181
6313
  var RESET11 = "\x1B[0m";
6182
6314
  function readV4Essence2(projectRoot) {
6183
6315
  const essencePath = join27(projectRoot, "decantr.essence.json");
6184
6316
  if (!existsSync25(essencePath)) {
6185
- console.error(`${RED10}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6317
+ console.error(`${RED9}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6186
6318
  process.exitCode = 1;
6187
6319
  return null;
6188
6320
  }
@@ -6190,13 +6322,13 @@ function readV4Essence2(projectRoot) {
6190
6322
  try {
6191
6323
  parsed = JSON.parse(readFileSync18(essencePath, "utf-8"));
6192
6324
  } catch (e) {
6193
- console.error(`${RED10}Could not read essence: ${e.message}${RESET11}`);
6325
+ console.error(`${RED9}Could not read essence: ${e.message}${RESET11}`);
6194
6326
  process.exitCode = 1;
6195
6327
  return null;
6196
6328
  }
6197
6329
  if (!isV47(parsed)) {
6198
6330
  console.error(
6199
- `${RED10}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6331
+ `${RED9}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6200
6332
  );
6201
6333
  process.exitCode = 1;
6202
6334
  return null;
@@ -6206,6 +6338,15 @@ function readV4Essence2(projectRoot) {
6206
6338
  function writeEssence2(essencePath, essence) {
6207
6339
  writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n");
6208
6340
  }
6341
+ function readFlagValue2(args, name) {
6342
+ const prefix = `--${name}=`;
6343
+ for (let index = 0; index < args.length; index += 1) {
6344
+ const arg = args[index];
6345
+ if (arg === `--${name}` && args[index + 1]) return args[index + 1];
6346
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
6347
+ }
6348
+ return void 0;
6349
+ }
6209
6350
  function recomputeGlobalFeatures(essence) {
6210
6351
  const all = /* @__PURE__ */ new Set();
6211
6352
  for (const section of essence.blueprint.sections || []) {
@@ -6228,7 +6369,7 @@ function removeRoutes(essence, sectionId, pageId) {
6228
6369
  }
6229
6370
  async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6230
6371
  if (!sectionId) {
6231
- console.error(`${RED10}Usage: decantr remove section <sectionId>${RESET11}`);
6372
+ console.error(`${RED9}Usage: decantr remove section <sectionId>${RESET11}`);
6232
6373
  process.exitCode = 1;
6233
6374
  return;
6234
6375
  }
@@ -6238,7 +6379,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6238
6379
  const sections = essence.blueprint.sections;
6239
6380
  const idx = sections.findIndex((s) => s.id === sectionId);
6240
6381
  if (idx === -1) {
6241
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6382
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6242
6383
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6243
6384
  process.exitCode = 1;
6244
6385
  return;
@@ -6260,7 +6401,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6260
6401
  }
6261
6402
  async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6262
6403
  if (!path || !path.includes("/")) {
6263
- console.error(`${RED10}Usage: decantr remove page <section>/<page>${RESET11}`);
6404
+ console.error(`${RED9}Usage: decantr remove page <section>/<page>${RESET11}`);
6264
6405
  console.error(`${DIM11}Example: decantr remove page settings/notifications${RESET11}`);
6265
6406
  process.exitCode = 1;
6266
6407
  return;
@@ -6272,14 +6413,14 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6272
6413
  const sections = essence.blueprint.sections;
6273
6414
  const section = sections.find((s) => s.id === sectionId);
6274
6415
  if (!section) {
6275
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6416
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6276
6417
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6277
6418
  process.exitCode = 1;
6278
6419
  return;
6279
6420
  }
6280
6421
  const pageIdx = section.pages.findIndex((p) => p.id === pageId);
6281
6422
  if (pageIdx === -1) {
6282
- console.error(`${RED10}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6423
+ console.error(`${RED9}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6283
6424
  console.error(`${DIM11}Available pages: ${section.pages.map((p) => p.id).join(", ")}${RESET11}`);
6284
6425
  process.exitCode = 1;
6285
6426
  return;
@@ -6296,7 +6437,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6296
6437
  }
6297
6438
  async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6298
6439
  if (!feature) {
6299
- console.error(`${RED10}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6440
+ console.error(`${RED9}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6300
6441
  process.exitCode = 1;
6301
6442
  return;
6302
6443
  }
@@ -6304,15 +6445,12 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6304
6445
  if (!loaded) return;
6305
6446
  const { essence, essencePath } = loaded;
6306
6447
  let sectionId;
6307
- const sectionIdx = args.indexOf("--section");
6308
- if (sectionIdx !== -1 && args[sectionIdx + 1]) {
6309
- sectionId = args[sectionIdx + 1];
6310
- }
6448
+ sectionId = readFlagValue2(args, "section");
6311
6449
  if (sectionId) {
6312
6450
  const sections = essence.blueprint.sections;
6313
6451
  const section = sections.find((s) => s.id === sectionId);
6314
6452
  if (!section) {
6315
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6453
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6316
6454
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6317
6455
  process.exitCode = 1;
6318
6456
  return;
@@ -6340,7 +6478,7 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6340
6478
  import { existsSync as existsSync26, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
6341
6479
  import { join as join28 } from "path";
6342
6480
  var GREEN12 = "\x1B[32m";
6343
- var RED11 = "\x1B[31m";
6481
+ var RED10 = "\x1B[31m";
6344
6482
  var YELLOW7 = "\x1B[33m";
6345
6483
  var RESET12 = "\x1B[0m";
6346
6484
  var DIM12 = "\x1B[2m";
@@ -6359,12 +6497,12 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
6359
6497
  try {
6360
6498
  entries = JSON.parse(readFileSync19(driftLogPath, "utf-8"));
6361
6499
  } catch {
6362
- console.error(`${RED11}Could not parse drift-log.json${RESET12}`);
6500
+ console.error(`${RED10}Could not parse drift-log.json${RESET12}`);
6363
6501
  process.exitCode = 1;
6364
6502
  return;
6365
6503
  }
6366
6504
  if (!Array.isArray(entries)) {
6367
- console.error(`${RED11}drift-log.json is not an array${RESET12}`);
6505
+ console.error(`${RED10}drift-log.json is not an array${RESET12}`);
6368
6506
  process.exitCode = 1;
6369
6507
  return;
6370
6508
  }
@@ -6382,7 +6520,7 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6382
6520
  `);
6383
6521
  for (let i = 0; i < unresolved.length; i++) {
6384
6522
  const entry = unresolved[i];
6385
- const severityColor = entry.severity === "error" ? RED11 : YELLOW7;
6523
+ const severityColor = entry.severity === "error" ? RED10 : YELLOW7;
6386
6524
  const icon = entry.severity === "error" ? "x" : "!";
6387
6525
  console.log(
6388
6526
  ` ${severityColor}${icon}${RESET12} ${BOLD6}#${i + 1}${RESET12} [${entry.rule}] ${entry.message}`
@@ -6665,7 +6803,7 @@ import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSy
6665
6803
  import { join as join29 } from "path";
6666
6804
  import { isV4 as isV48 } from "@decantr/essence-spec";
6667
6805
  var GREEN14 = "\x1B[32m";
6668
- var RED12 = "\x1B[31m";
6806
+ var RED11 = "\x1B[31m";
6669
6807
  var YELLOW8 = "\x1B[33m";
6670
6808
  var DIM14 = "\x1B[2m";
6671
6809
  var RESET14 = "\x1B[0m";
@@ -6674,14 +6812,14 @@ var VALID_THEME_MODES = ["light", "dark", "auto"];
6674
6812
  async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6675
6813
  if (!themeName) {
6676
6814
  console.error(
6677
- `${RED12}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6815
+ `${RED11}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6678
6816
  );
6679
6817
  process.exitCode = 1;
6680
6818
  return;
6681
6819
  }
6682
6820
  const essencePath = join29(projectRoot, "decantr.essence.json");
6683
6821
  if (!existsSync27(essencePath)) {
6684
- console.error(`${RED12}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6822
+ console.error(`${RED11}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6685
6823
  process.exitCode = 1;
6686
6824
  return;
6687
6825
  }
@@ -6689,13 +6827,13 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6689
6827
  try {
6690
6828
  parsed = JSON.parse(readFileSync20(essencePath, "utf-8"));
6691
6829
  } catch (e) {
6692
- console.error(`${RED12}Could not read essence: ${e.message}${RESET14}`);
6830
+ console.error(`${RED11}Could not read essence: ${e.message}${RESET14}`);
6693
6831
  process.exitCode = 1;
6694
6832
  return;
6695
6833
  }
6696
6834
  if (!isV48(parsed)) {
6697
6835
  console.error(
6698
- `${RED12}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6836
+ `${RED11}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6699
6837
  );
6700
6838
  process.exitCode = 1;
6701
6839
  return;
@@ -6717,14 +6855,14 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6717
6855
  }
6718
6856
  if (shape && !VALID_THEME_SHAPES.includes(shape)) {
6719
6857
  console.error(
6720
- `${RED12}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6858
+ `${RED11}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6721
6859
  );
6722
6860
  process.exitCode = 1;
6723
6861
  return;
6724
6862
  }
6725
6863
  if (mode && !VALID_THEME_MODES.includes(mode)) {
6726
6864
  console.error(
6727
- `${RED12}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6865
+ `${RED11}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6728
6866
  );
6729
6867
  process.exitCode = 1;
6730
6868
  return;
@@ -7228,7 +7366,7 @@ function importTheme(projectRoot, sourcePath) {
7228
7366
  var BOLD9 = "\x1B[1m";
7229
7367
  var DIM16 = "\x1B[2m";
7230
7368
  var RESET16 = "\x1B[0m";
7231
- var RED13 = "\x1B[31m";
7369
+ var RED12 = "\x1B[31m";
7232
7370
  var GREEN16 = "\x1B[32m";
7233
7371
  var CYAN9 = "\x1B[36m";
7234
7372
  var YELLOW10 = "\x1B[33m";
@@ -7240,8 +7378,8 @@ ${BOLD9}${text}${RESET16}
7240
7378
  function success3(text) {
7241
7379
  return `${GREEN16}${text}${RESET16}`;
7242
7380
  }
7243
- function error3(text) {
7244
- return `${RED13}${text}${RESET16}`;
7381
+ function error2(text) {
7382
+ return `${RED12}${text}${RESET16}`;
7245
7383
  }
7246
7384
  function dim3(text) {
7247
7385
  return `${DIM16}${text}${RESET16}`;
@@ -7751,7 +7889,7 @@ function getPublicAPIClient() {
7751
7889
  });
7752
7890
  }
7753
7891
  function resolveUserPath(inputPath, cwd = process.cwd()) {
7754
- return isAbsolute(inputPath) ? inputPath : resolve4(cwd, inputPath);
7892
+ return isAbsolute3(inputPath) ? inputPath : resolve4(cwd, inputPath);
7755
7893
  }
7756
7894
  function extractHostedAssetPaths(indexHtml) {
7757
7895
  const assetPaths = /* @__PURE__ */ new Set();
@@ -8345,22 +8483,22 @@ function patternCandidateFromRegistryItem(item, source) {
8345
8483
  { source, slug }
8346
8484
  );
8347
8485
  }
8348
- function readSuggestCodeContext(route, file) {
8486
+ function readSuggestCodeContext(projectRoot, route, file) {
8349
8487
  const pieces = [];
8350
8488
  if (file) {
8351
- const resolved = isAbsolute(file) ? file : join31(process.cwd(), file);
8489
+ const resolved = isAbsolute3(file) ? file : join31(projectRoot, file);
8352
8490
  if (existsSync29(resolved)) {
8353
8491
  pieces.push(readFileSync22(resolved, "utf-8"));
8354
8492
  }
8355
8493
  }
8356
8494
  if (route) {
8357
- const analysisPath = join31(process.cwd(), ".decantr", "analysis.json");
8495
+ const analysisPath = join31(projectRoot, ".decantr", "analysis.json");
8358
8496
  if (existsSync29(analysisPath)) {
8359
8497
  try {
8360
8498
  const analysis = JSON.parse(readFileSync22(analysisPath, "utf-8"));
8361
8499
  const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
8362
8500
  if (routeEntry?.file) {
8363
- const resolved = join31(process.cwd(), routeEntry.file);
8501
+ const resolved = join31(projectRoot, routeEntry.file);
8364
8502
  if (existsSync29(resolved)) {
8365
8503
  pieces.push(readFileSync22(resolved, "utf-8"));
8366
8504
  }
@@ -8371,6 +8509,28 @@ function readSuggestCodeContext(route, file) {
8371
8509
  }
8372
8510
  return pieces.join("\n\n").slice(0, 2e4);
8373
8511
  }
8512
+ function localPatternMatches(projectRoot, query) {
8513
+ if (!projectRoot) return [];
8514
+ const pack = readLocalPatternPack(projectRoot);
8515
+ const patterns = Array.isArray(pack?.patterns) ? pack.patterns : [];
8516
+ const queryTerms = query.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1);
8517
+ if (queryTerms.length === 0) return [];
8518
+ return patterns.map((pattern) => {
8519
+ const id = typeof pattern.id === "string" ? pattern.id : "local-pattern";
8520
+ const label = typeof pattern.label === "string" ? pattern.label : null;
8521
+ const role = typeof pattern.role === "string" ? pattern.role : null;
8522
+ const haystack = [
8523
+ id,
8524
+ label,
8525
+ role,
8526
+ typeof pattern.decide === "string" ? pattern.decide : null,
8527
+ ...Array.isArray(pattern.appliesTo) ? pattern.appliesTo : [],
8528
+ ...Array.isArray(pattern.componentPaths) ? pattern.componentPaths : []
8529
+ ].filter((entry) => typeof entry === "string").join(" ").toLowerCase();
8530
+ const score = queryTerms.reduce((sum, term) => sum + (haystack.includes(term) ? 1 : 0), 0);
8531
+ return { id, label, role, score };
8532
+ }).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, 5);
8533
+ }
8374
8534
  async function loadPatternDiscoveryCandidates(registryClient) {
8375
8535
  const candidates = [];
8376
8536
  const seen = /* @__PURE__ */ new Set();
@@ -8419,9 +8579,9 @@ async function cmdSuggest(query, options = {}) {
8419
8579
  }
8420
8580
  }
8421
8581
  const registryClient = new RegistryClient({
8422
- cacheDir: join31(process.cwd(), ".decantr", "cache")
8582
+ cacheDir: join31(options.projectRoot ?? process.cwd(), ".decantr", "cache")
8423
8583
  });
8424
- const code = options.fromCode || options.file ? readSuggestCodeContext(options.route, options.file) : "";
8584
+ const code = options.fromCode || options.file ? readSuggestCodeContext(options.projectRoot ?? process.cwd(), options.route, options.file) : "";
8425
8585
  const candidates = await loadPatternDiscoveryCandidates(registryClient);
8426
8586
  const matches = rankPatternCandidates(
8427
8587
  {
@@ -8452,6 +8612,16 @@ async function cmdSuggest(query, options = {}) {
8452
8612
  `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
8453
8613
  )
8454
8614
  );
8615
+ const localMatches = localPatternMatches(options.projectRoot, query);
8616
+ if (localMatches.length > 0) {
8617
+ console.log(`${BOLD9}Project-owned local law:${RESET16}`);
8618
+ for (const match of localMatches) {
8619
+ const details = [match.label, match.role].filter(Boolean).join(" | ");
8620
+ console.log(` ${cyan3(match.id)}${details ? ` ${dim3(details)}` : ""}`);
8621
+ }
8622
+ console.log("");
8623
+ console.log(`${BOLD9}Registry patterns:${RESET16}`);
8624
+ }
8455
8625
  for (const match of matches.slice(0, 8)) {
8456
8626
  const candidate = match.candidate;
8457
8627
  const slug = candidate.slug || candidate.id;
@@ -8475,7 +8645,7 @@ async function cmdSuggest(query, options = {}) {
8475
8645
  }
8476
8646
  async function cmdGet(type, id) {
8477
8647
  if (!isGetContentType(type)) {
8478
- console.error(error3(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8648
+ console.error(error2(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8479
8649
  process.exitCode = 1;
8480
8650
  return;
8481
8651
  }
@@ -8493,7 +8663,7 @@ async function cmdGet(type, id) {
8493
8663
  console.log(JSON.stringify(bundled.data, null, 2));
8494
8664
  return;
8495
8665
  }
8496
- console.error(error3(`${type} "${id}" not found.`));
8666
+ console.error(error2(`${type} "${id}" not found.`));
8497
8667
  process.exitCode = 1;
8498
8668
  return;
8499
8669
  }
@@ -8503,7 +8673,7 @@ async function cmdValidate(path) {
8503
8673
  try {
8504
8674
  raw = readFileSync22(essencePath, "utf-8");
8505
8675
  } catch {
8506
- console.error(error3(`Could not read ${essencePath}`));
8676
+ console.error(error2(`Could not read ${essencePath}`));
8507
8677
  process.exitCode = 1;
8508
8678
  return;
8509
8679
  }
@@ -8511,7 +8681,7 @@ async function cmdValidate(path) {
8511
8681
  try {
8512
8682
  essence = JSON.parse(raw);
8513
8683
  } catch (e) {
8514
- console.error(error3(`Invalid JSON: ${e.message}`));
8684
+ console.error(error2(`Invalid JSON: ${e.message}`));
8515
8685
  process.exitCode = 1;
8516
8686
  return;
8517
8687
  }
@@ -8521,9 +8691,9 @@ async function cmdValidate(path) {
8521
8691
  if (result.valid) {
8522
8692
  console.log(success3(`Essence is valid (${detectedVersion}).`));
8523
8693
  } else {
8524
- console.error(error3("Validation failed:"));
8694
+ console.error(error2("Validation failed:"));
8525
8695
  for (const err of result.errors) {
8526
- console.error(` ${RED13}${err}${RESET16}`);
8696
+ console.error(` ${RED12}${err}${RESET16}`);
8527
8697
  }
8528
8698
  process.exitCode = 1;
8529
8699
  return;
@@ -8562,7 +8732,7 @@ async function cmdValidate(path) {
8562
8732
  async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet) {
8563
8733
  if (!isApiContentType(type)) {
8564
8734
  console.error(
8565
- error3(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8735
+ error2(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8566
8736
  );
8567
8737
  process.exitCode = 1;
8568
8738
  return;
@@ -8724,7 +8894,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8724
8894
  const proposal = readBrownfieldProposal(input.projectRoot);
8725
8895
  if (!proposal) {
8726
8896
  console.log(
8727
- error3(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8897
+ error2(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8728
8898
  );
8729
8899
  console.log(
8730
8900
  dim3(
@@ -8739,7 +8909,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8739
8909
  let essence;
8740
8910
  let backupPath = null;
8741
8911
  if (input.mode === "accept" && hasEssence) {
8742
- console.log(error3("Refusing to accept proposal over an existing decantr.essence.json."));
8912
+ console.log(error2("Refusing to accept proposal over an existing decantr.essence.json."));
8743
8913
  console.log(
8744
8914
  dim3(
8745
8915
  "Use `--merge-proposal` to preserve the existing contract or `--replace-essence` for an explicit destructive replacement."
@@ -8752,7 +8922,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8752
8922
  const existing = JSON.parse(readFileSync22(essencePath, "utf-8"));
8753
8923
  if (!isV49(existing)) {
8754
8924
  console.log(
8755
- error3(
8925
+ error2(
8756
8926
  "Existing essence is not v4. Run `decantr migrate --to v4` before merging a brownfield proposal."
8757
8927
  )
8758
8928
  );
@@ -8766,10 +8936,10 @@ async function applyAcceptedBrownfieldProposal(input) {
8766
8936
  const validation = validateEssence2(essence);
8767
8937
  if (!validation.valid) {
8768
8938
  console.log(
8769
- error3("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8939
+ error2("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8770
8940
  );
8771
8941
  for (const validationError of validation.errors) {
8772
- console.log(` ${RED13}${validationError}${RESET16}`);
8942
+ console.log(` ${RED12}${validationError}${RESET16}`);
8773
8943
  }
8774
8944
  process.exitCode = 1;
8775
8945
  return;
@@ -8815,13 +8985,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8815
8985
  }
8816
8986
  const appliedRuleFiles = input.assistantBridge === "apply" ? applyAssistantBridge(input.projectRoot, input.detected) : [];
8817
8987
  console.log(success3("\nBrownfield proposal accepted.\n"));
8988
+ const projectLabel = input.workspaceInfo.appRoot !== input.workspaceInfo.workspaceRoot ? relative7(input.workspaceInfo.workspaceRoot, input.workspaceInfo.appRoot).replace(/\\/g, "/") : void 0;
8818
8989
  console.log(" Files created/updated:");
8819
- console.log(` ${cyan3("decantr.essence.json")} Observed brownfield contract`);
8820
- console.log(` ${cyan3("DECANTR.md")} Reconciled assistant guidance`);
8821
- console.log(` ${cyan3(".decantr/project.json")} Brownfield attach metadata`);
8822
- console.log(` ${cyan3(".decantr/context/")} Generated contract context`);
8990
+ console.log(
8991
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "decantr.essence.json"))} Observed brownfield contract`
8992
+ );
8993
+ console.log(
8994
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "DECANTR.md"))} Reconciled assistant guidance`
8995
+ );
8996
+ console.log(
8997
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/project.json"))} Brownfield attach metadata`
8998
+ );
8999
+ console.log(
9000
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/"))} Generated contract context`
9001
+ );
8823
9002
  if (assistantBridgePath) {
8824
- console.log(` ${cyan3(".decantr/context/assistant-bridge.md")} Assistant bridge preview`);
9003
+ console.log(
9004
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/assistant-bridge.md"))} Assistant bridge preview`
9005
+ );
8825
9006
  }
8826
9007
  if (appliedRuleFiles.length > 0) {
8827
9008
  console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
@@ -8832,16 +9013,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8832
9013
  console.log("");
8833
9014
  console.log(" Generated context:");
8834
9015
  for (const contextFile of refreshResult.contextFiles.slice(0, 8)) {
8835
- console.log(` ${dim3(contextFile.replace(`${input.projectRoot}/`, ""))}`);
9016
+ console.log(
9017
+ ` ${dim3(displayProjectPath(input.workspaceInfo, contextFile.replace(`${input.projectRoot}/`, "")))}`
9018
+ );
8836
9019
  }
8837
9020
  if (refreshResult.contextFiles.length > 8) {
8838
9021
  console.log(` ${dim3(`(+${refreshResult.contextFiles.length - 8} more)`)}`);
8839
9022
  }
8840
9023
  console.log("");
8841
9024
  console.log(" Next steps:");
8842
- console.log(` 1. Run ${cyan3("decantr check --brownfield")} to verify contract coverage`);
8843
- console.log(` 2. Read ${cyan3(".decantr/brownfield-report.md")} for unresolved doctrine risks`);
8844
- console.log(` 3. Use ${cyan3("decantr rules preview")} before mutating assistant rule files`);
9025
+ console.log(
9026
+ ` 1. Run ${cyan3(withProject("decantr check --brownfield", projectLabel))} to verify contract coverage`
9027
+ );
9028
+ console.log(
9029
+ ` 2. Read ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/brownfield-report.md"))} for unresolved doctrine risks`
9030
+ );
9031
+ console.log(
9032
+ ` 3. Use ${cyan3(withProject("decantr rules preview", projectLabel))} before mutating assistant rule files`
9033
+ );
8845
9034
  console.log("");
8846
9035
  }
8847
9036
  async function cmdInit(args) {
@@ -8898,7 +9087,7 @@ async function cmdInit(args) {
8898
9087
  }
8899
9088
  if (policy.workflowMode === "brownfield-attach" && detected.existingEssence) {
8900
9089
  console.log(
8901
- error3("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
9090
+ error2("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
8902
9091
  );
8903
9092
  console.log(
8904
9093
  dim3(
@@ -8909,7 +9098,7 @@ async function cmdInit(args) {
8909
9098
  return;
8910
9099
  }
8911
9100
  if (policy.workflowMode === "brownfield-attach" && readBrownfieldProposal(projectRoot)) {
8912
- console.log(error3("Observed brownfield proposal found, but it was not accepted."));
9101
+ console.log(error2("Observed brownfield proposal found, but it was not accepted."));
8913
9102
  console.log(
8914
9103
  dim3(
8915
9104
  "Review `.decantr/brownfield-report.md`, then run `decantr init --existing --accept-proposal`."
@@ -8930,7 +9119,7 @@ async function cmdInit(args) {
8930
9119
  console.log(dim3(` Seeded offline registry content from ${offlineSeed.strategy}.`));
8931
9120
  } else if (requestedBlueprint || requestedArchetype) {
8932
9121
  console.log(
8933
- error3("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
9122
+ error2("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
8934
9123
  );
8935
9124
  console.log(
8936
9125
  dim3(
@@ -8998,7 +9187,7 @@ ${YELLOW10}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
8998
9187
  }
8999
9188
  if (requestedBlueprint || requestedArchetype) {
9000
9189
  console.log(
9001
- error3(
9190
+ error2(
9002
9191
  "\nThe requested blueprint/archetype could not be resolved from the hosted registry or local cache."
9003
9192
  )
9004
9193
  );
@@ -9187,7 +9376,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9187
9376
  }
9188
9377
  } else {
9189
9378
  if (requestedBlueprint) {
9190
- console.log(error3(` Error: Could not fetch blueprint "${options.blueprint}".`));
9379
+ console.log(error2(` Error: Could not fetch blueprint "${options.blueprint}".`));
9191
9380
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9192
9381
  process.exitCode = 1;
9193
9382
  return;
@@ -9202,7 +9391,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9202
9391
  archetypeData = mapRegistryArchetypeToArchetypeData(archetypeResult.data);
9203
9392
  } else {
9204
9393
  if (requestedArchetype) {
9205
- console.log(error3(` Error: Could not fetch archetype "${options.archetype}".`));
9394
+ console.log(error2(` Error: Could not fetch archetype "${options.archetype}".`));
9206
9395
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9207
9396
  process.exitCode = 1;
9208
9397
  return;
@@ -9219,7 +9408,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9219
9408
  themeData = mapRegistryThemeToThemeData(themeResult.data);
9220
9409
  } else {
9221
9410
  if (requestedTheme) {
9222
- console.log(error3(` Error: Could not fetch theme "${options.theme}".`));
9411
+ console.log(error2(` Error: Could not fetch theme "${options.theme}".`));
9223
9412
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9224
9413
  process.exitCode = 1;
9225
9414
  return;
@@ -9329,7 +9518,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9329
9518
  const essence = JSON.parse(essenceContent);
9330
9519
  const validation = validateEssence2(essence);
9331
9520
  if (!validation.valid) {
9332
- console.log(error3(`
9521
+ console.log(error2(`
9333
9522
  Validation warnings: ${validation.errors.join(", ")}`));
9334
9523
  }
9335
9524
  console.log("");
@@ -9379,13 +9568,12 @@ Validation warnings: ${validation.errors.join(", ")}`));
9379
9568
  console.log(dim3('Run "decantr sync" when online to get the latest registry content.'));
9380
9569
  }
9381
9570
  }
9382
- async function cmdStatus() {
9383
- const projectRoot = process.cwd();
9571
+ async function cmdStatus(projectRoot = process.cwd()) {
9384
9572
  const essencePath = join31(projectRoot, "decantr.essence.json");
9385
9573
  const projectJsonPath = join31(projectRoot, ".decantr", "project.json");
9386
9574
  console.log(heading2("Decantr Project Status"));
9387
9575
  if (!existsSync29(essencePath)) {
9388
- console.log(`${RED13}No decantr.essence.json found.${RESET16}`);
9576
+ console.log(`${RED12}No decantr.essence.json found.${RESET16}`);
9389
9577
  console.log(dim3('Run "decantr init" to create one.'));
9390
9578
  return;
9391
9579
  }
@@ -9397,7 +9585,7 @@ async function cmdStatus() {
9397
9585
  if (validation.valid) {
9398
9586
  console.log(` ${GREEN16}Valid${RESET16} (${essenceVersion})`);
9399
9587
  } else {
9400
- console.log(` ${RED13}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9588
+ console.log(` ${RED12}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9401
9589
  }
9402
9590
  if (isV49(essence)) {
9403
9591
  const v4 = essence;
@@ -9434,7 +9622,7 @@ async function cmdStatus() {
9434
9622
  console.log(` ${YELLOW10}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9435
9623
  }
9436
9624
  } catch (e) {
9437
- console.log(` ${RED13}Error reading essence: ${e.message}${RESET16}`);
9625
+ console.log(` ${RED12}Error reading essence: ${e.message}${RESET16}`);
9438
9626
  }
9439
9627
  console.log("");
9440
9628
  console.log(`${BOLD9}Sync Status:${RESET16}`);
@@ -9480,7 +9668,7 @@ function printVerificationFindings(findings) {
9480
9668
  return;
9481
9669
  }
9482
9670
  for (const finding of findings) {
9483
- const color = finding.severity === "error" ? RED13 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9671
+ const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9484
9672
  console.log(
9485
9673
  ` ${color}[${finding.severity.toUpperCase()}]${RESET16} ${finding.category}: ${finding.message}`
9486
9674
  );
@@ -9496,7 +9684,7 @@ function printProjectAuditReport(report) {
9496
9684
  if (report.valid) {
9497
9685
  console.log(success3("Project contract is valid."));
9498
9686
  } else {
9499
- console.log(`${RED13}Project audit found blocking issues.${RESET16}`);
9687
+ console.log(`${RED12}Project audit found blocking issues.${RESET16}`);
9500
9688
  }
9501
9689
  console.log("");
9502
9690
  console.log(`${BOLD9}Summary:${RESET16}`);
@@ -9585,13 +9773,12 @@ async function cmdAudit(filePath) {
9585
9773
  console.log(dim3("Project audit completed with advisory findings."));
9586
9774
  }
9587
9775
  } catch (e) {
9588
- console.log(`${RED13}Error: ${e.message}${RESET16}`);
9776
+ console.log(`${RED12}Error: ${e.message}${RESET16}`);
9589
9777
  process.exitCode = 1;
9590
9778
  }
9591
9779
  }
9592
- async function cmdTheme(args) {
9780
+ async function cmdTheme(args, projectRoot = process.cwd()) {
9593
9781
  const subcommand = args[0];
9594
- const projectRoot = process.cwd();
9595
9782
  if (!subcommand || subcommand === "help") {
9596
9783
  console.log(`
9597
9784
  ${BOLD9}decantr theme${RESET16} \u2014 Manage custom themes
@@ -9616,7 +9803,7 @@ ${BOLD9}Examples:${RESET16}
9616
9803
  case "create": {
9617
9804
  const name = args[1];
9618
9805
  if (!name) {
9619
- console.error(error3("Usage: decantr theme create <name>"));
9806
+ console.error(error2("Usage: decantr theme create <name>"));
9620
9807
  process.exitCode = 1;
9621
9808
  return;
9622
9809
  }
@@ -9628,7 +9815,7 @@ ${BOLD9}Examples:${RESET16}
9628
9815
  console.log("");
9629
9816
  console.log(`Use in essence: ${cyan3(`"id": "custom:${name}"`)}`);
9630
9817
  } else {
9631
- console.error(error3(result.error || "Failed to create theme"));
9818
+ console.error(error2(result.error || "Failed to create theme"));
9632
9819
  process.exitCode = 1;
9633
9820
  }
9634
9821
  break;
@@ -9649,13 +9836,13 @@ ${BOLD9}Examples:${RESET16}
9649
9836
  case "validate": {
9650
9837
  const name = args[1];
9651
9838
  if (!name) {
9652
- console.error(error3("Usage: decantr theme validate <name>"));
9839
+ console.error(error2("Usage: decantr theme validate <name>"));
9653
9840
  process.exitCode = 1;
9654
9841
  return;
9655
9842
  }
9656
9843
  const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
9657
9844
  if (!existsSync29(themePath)) {
9658
- console.error(error3(`Theme "${name}" not found at ${themePath}`));
9845
+ console.error(error2(`Theme "${name}" not found at ${themePath}`));
9659
9846
  process.exitCode = 1;
9660
9847
  return;
9661
9848
  }
@@ -9665,14 +9852,14 @@ ${BOLD9}Examples:${RESET16}
9665
9852
  if (result.valid) {
9666
9853
  console.log(success3(`Custom theme "${name}" is valid`));
9667
9854
  } else {
9668
- console.error(error3("Validation failed:"));
9855
+ console.error(error2("Validation failed:"));
9669
9856
  for (const err of result.errors) {
9670
- console.error(` ${RED13}${err}${RESET16}`);
9857
+ console.error(` ${RED12}${err}${RESET16}`);
9671
9858
  }
9672
9859
  process.exitCode = 1;
9673
9860
  }
9674
9861
  } catch (e) {
9675
- console.error(error3(`Invalid JSON: ${e.message}`));
9862
+ console.error(error2(`Invalid JSON: ${e.message}`));
9676
9863
  process.exitCode = 1;
9677
9864
  }
9678
9865
  break;
@@ -9680,7 +9867,7 @@ ${BOLD9}Examples:${RESET16}
9680
9867
  case "delete": {
9681
9868
  const name = args[1];
9682
9869
  if (!name) {
9683
- console.error(error3("Usage: decantr theme delete <name>"));
9870
+ console.error(error2("Usage: decantr theme delete <name>"));
9684
9871
  process.exitCode = 1;
9685
9872
  return;
9686
9873
  }
@@ -9688,7 +9875,7 @@ ${BOLD9}Examples:${RESET16}
9688
9875
  if (result.success) {
9689
9876
  console.log(success3(`Deleted custom theme "${name}"`));
9690
9877
  } else {
9691
- console.error(error3(result.error || "Failed to delete theme"));
9878
+ console.error(error2(result.error || "Failed to delete theme"));
9692
9879
  process.exitCode = 1;
9693
9880
  }
9694
9881
  break;
@@ -9696,7 +9883,7 @@ ${BOLD9}Examples:${RESET16}
9696
9883
  case "import": {
9697
9884
  const sourcePath = args[1];
9698
9885
  if (!sourcePath) {
9699
- console.error(error3("Usage: decantr theme import <path>"));
9886
+ console.error(error2("Usage: decantr theme import <path>"));
9700
9887
  process.exitCode = 1;
9701
9888
  return;
9702
9889
  }
@@ -9705,9 +9892,9 @@ ${BOLD9}Examples:${RESET16}
9705
9892
  console.log(success3("Theme imported successfully"));
9706
9893
  console.log(dim3(` Path: ${result.path}`));
9707
9894
  } else {
9708
- console.error(error3("Import failed:"));
9895
+ console.error(error2("Import failed:"));
9709
9896
  for (const err of result.errors || []) {
9710
- console.error(` ${RED13}${err}${RESET16}`);
9897
+ console.error(` ${RED12}${err}${RESET16}`);
9711
9898
  }
9712
9899
  process.exitCode = 1;
9713
9900
  }
@@ -9716,7 +9903,7 @@ ${BOLD9}Examples:${RESET16}
9716
9903
  case "switch": {
9717
9904
  const name = args[1];
9718
9905
  if (!name) {
9719
- console.error(error3("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9906
+ console.error(error2("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9720
9907
  process.exitCode = 1;
9721
9908
  return;
9722
9909
  }
@@ -9724,7 +9911,7 @@ ${BOLD9}Examples:${RESET16}
9724
9911
  break;
9725
9912
  }
9726
9913
  default:
9727
- console.error(error3(`Unknown theme command: ${subcommand}`));
9914
+ console.error(error2(`Unknown theme command: ${subcommand}`));
9728
9915
  process.exitCode = 1;
9729
9916
  }
9730
9917
  }
@@ -9791,6 +9978,44 @@ function withoutWorkflowOnlyFlags(args) {
9791
9978
  function withProject(command, projectArg) {
9792
9979
  return projectArg ? `${command} --project ${projectArg}` : command;
9793
9980
  }
9981
+ function displayProjectPath(workspaceInfo, projectPath) {
9982
+ const absolutePath = join31(workspaceInfo.appRoot, projectPath);
9983
+ const relativePath = relative7(workspaceInfo.cwd, absolutePath).replace(/\\/g, "/");
9984
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute3(relativePath)) {
9985
+ return relativePath;
9986
+ }
9987
+ return absolutePath;
9988
+ }
9989
+ function stripProjectArgs(args, startIndex = 1) {
9990
+ const stripped = [args[0]];
9991
+ for (let index = startIndex; index < args.length; index += 1) {
9992
+ const arg = args[index];
9993
+ if (arg === "--project" && args[index + 1]) {
9994
+ index += 1;
9995
+ continue;
9996
+ }
9997
+ if (arg.startsWith("--project=")) continue;
9998
+ stripped.push(arg);
9999
+ }
10000
+ return stripped;
10001
+ }
10002
+ function normalizedProjectPath(value) {
10003
+ if (!value) return null;
10004
+ return value.replace(/\\/g, "/").replace(/\/+$/g, "");
10005
+ }
10006
+ function printProjectNotFound(projectArg, commandName) {
10007
+ console.error(error2(`decantr ${commandName} could not find project path: ${projectArg}`));
10008
+ console.error(dim3("Pass an existing app path, for example `--project apps/web`."));
10009
+ }
10010
+ function ensureAllowedFlags(flags, allowed, commandName) {
10011
+ const allowedSet = new Set(allowed);
10012
+ const unknown = Object.keys(flags).filter((flag) => !allowedSet.has(flag));
10013
+ if (unknown.length === 0) return true;
10014
+ console.error(error2(`Unsupported option for decantr ${commandName}: --${unknown[0]}`));
10015
+ console.error(dim3("Run `decantr help` or the command-specific help to see supported options."));
10016
+ process.exitCode = 1;
10017
+ return false;
10018
+ }
9794
10019
  function compilePacksCommandForProject(projectArg) {
9795
10020
  const essencePath = projectArg ? `${projectArg}/decantr.essence.json` : "decantr.essence.json";
9796
10021
  return `decantr registry compile-packs ${essencePath} --write-context`;
@@ -9801,7 +10026,7 @@ function firstWorkspaceCandidate(workspaceInfo) {
9801
10026
  function printWorkspaceProjectSelection(workspaceInfo, commandName = "command") {
9802
10027
  const candidate = firstWorkspaceCandidate(workspaceInfo);
9803
10028
  const noun = commandName === "adopt" ? "Brownfield adoption" : `decantr ${commandName}`;
9804
- console.log(error3(`${noun} needs an app path.`));
10029
+ console.log(error2(`${noun} needs an app path.`));
9805
10030
  console.log("");
9806
10031
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9807
10032
  console.log("Install Decantr at the workspace root, then attach it to one app with --project.");
@@ -9821,10 +10046,47 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
9821
10046
  }
9822
10047
  function printMonorepoSetupGuidance(workspaceInfo) {
9823
10048
  const candidate = firstWorkspaceCandidate(workspaceInfo);
10049
+ const attachedProjects = workspaceInfo.appCandidates.filter(
10050
+ (appCandidate) => existsSync29(join31(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
10051
+ );
10052
+ const firstAttached = attachedProjects[0];
9824
10053
  console.log(heading2("Decantr Setup"));
9825
10054
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9826
10055
  console.log(` Workspace root: ${workspaceInfo.workspaceRoot}`);
9827
10056
  console.log("");
10057
+ if (firstAttached) {
10058
+ console.log("Decantr is already attached to at least one app.");
10059
+ console.log("");
10060
+ console.log("Attached projects:");
10061
+ for (const project of attachedProjects) {
10062
+ console.log(` ${project}`);
10063
+ }
10064
+ console.log("");
10065
+ console.log(`${BOLD9}Next:${RESET16}`);
10066
+ console.log(
10067
+ ` ${cyan3(`decantr doctor --project ${firstAttached}`)} Explain current state and next command`
10068
+ );
10069
+ console.log(
10070
+ ` ${cyan3(`decantr task <route> "<change>" --project ${firstAttached}`)} Prepare LLM context before edits`
10071
+ );
10072
+ console.log(
10073
+ ` ${cyan3(`decantr verify --brownfield --local-patterns --project ${firstAttached}`)} Check after edits`
10074
+ );
10075
+ console.log(
10076
+ ` ${cyan3(`decantr ci init --project ${firstAttached}`)} Wire the app into CI`
10077
+ );
10078
+ const unattached = workspaceInfo.appCandidates.filter(
10079
+ (appCandidate) => !attachedProjects.includes(appCandidate)
10080
+ );
10081
+ if (unattached.length > 0) {
10082
+ console.log("");
10083
+ console.log("Other app candidates:");
10084
+ for (const appCandidate of unattached) {
10085
+ console.log(` ${appCandidate}`);
10086
+ }
10087
+ }
10088
+ return;
10089
+ }
9828
10090
  console.log(
9829
10091
  "Install Decantr at the workspace root, then attach it to the app you want Decantr to govern."
9830
10092
  );
@@ -9850,9 +10112,34 @@ function printMonorepoSetupGuidance(workspaceInfo) {
9850
10112
  ` ${cyan3(`decantr verify --project ${candidate} --base-url http://localhost:3000 --evidence`)}`
9851
10113
  );
9852
10114
  }
9853
- function resolveWorkflowProject(flags, commandName = "command") {
10115
+ function resolveWorkflowProject(flags, commandName = "command", options = {}) {
9854
10116
  const projectArg = flagString(flags, "project");
9855
10117
  const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
10118
+ if (projectArg && options.requireExisting !== false && !existsSync29(workspaceInfo.appRoot)) {
10119
+ printProjectNotFound(projectArg, commandName);
10120
+ process.exitCode = 1;
10121
+ return null;
10122
+ }
10123
+ if (projectArg && options.requireAppCandidate && workspaceInfo.appCandidates.length > 0) {
10124
+ const normalizedProject = normalizedProjectPath(projectArg);
10125
+ const knownCandidate = normalizedProject ? workspaceInfo.appCandidates.includes(normalizedProject) : false;
10126
+ const forcePackage = flagBoolean(flags, "force-package") || flagBoolean(flags, "allow-package") || flagBoolean(flags, "force");
10127
+ if (!knownCandidate && !forcePackage && !options.allowPackageProject) {
10128
+ console.error(
10129
+ error2(`decantr ${commandName} is app-scoped, but "${projectArg}" is not an app candidate.`)
10130
+ );
10131
+ if (workspaceInfo.appCandidates.length > 0) {
10132
+ console.error(dim3(`App candidates: ${workspaceInfo.appCandidates.join(", ")}`));
10133
+ }
10134
+ console.error(
10135
+ dim3(
10136
+ "Use --force-package only if you intentionally want Decantr attached to a non-app package."
10137
+ )
10138
+ );
10139
+ process.exitCode = 1;
10140
+ return null;
10141
+ }
10142
+ }
9856
10143
  if (workspaceInfo.requiresProjectSelection) {
9857
10144
  printWorkspaceProjectSelection(workspaceInfo, commandName);
9858
10145
  process.exitCode = 1;
@@ -9921,7 +10208,37 @@ async function cmdSetupWorkflow(args) {
9921
10208
  }
9922
10209
  async function cmdAdoptWorkflow(args) {
9923
10210
  const { flags } = parseLooseArgs(args);
9924
- const workspaceInfo = resolveWorkflowProject(flags, "adopt");
10211
+ if (!ensureAllowedFlags(
10212
+ flags,
10213
+ [
10214
+ "project",
10215
+ "dry-run",
10216
+ "yes",
10217
+ "y",
10218
+ "base-url",
10219
+ "verify",
10220
+ "browser",
10221
+ "evidence",
10222
+ "baseline",
10223
+ "save-baseline",
10224
+ "packs",
10225
+ "skip-packs",
10226
+ "offline",
10227
+ "ci",
10228
+ "init-ci",
10229
+ "assistant-bridge",
10230
+ "replace-essence",
10231
+ "merge-proposal",
10232
+ "telemetry",
10233
+ "force-package",
10234
+ "allow-package",
10235
+ "force"
10236
+ ],
10237
+ "adopt"
10238
+ )) {
10239
+ return;
10240
+ }
10241
+ const workspaceInfo = resolveWorkflowProject(flags, "adopt", { requireAppCandidate: true });
9925
10242
  if (!workspaceInfo) return;
9926
10243
  const projectRoot = workspaceInfo.appRoot;
9927
10244
  const projectArg = flagString(flags, "project");
@@ -9992,9 +10309,7 @@ async function cmdAdoptWorkflow(args) {
9992
10309
  )
9993
10310
  );
9994
10311
  } catch (e) {
9995
- console.log(
9996
- `${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`
9997
- );
10312
+ console.log(`${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`);
9998
10313
  console.log(
9999
10314
  dim3(
10000
10315
  `Run ${compilePacksCommandForProject(projectArg)} after adoption if you want hosted page/review packs.`
@@ -10005,7 +10320,7 @@ async function cmdAdoptWorkflow(args) {
10005
10320
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
10006
10321
  }
10007
10322
  if (runVerify) {
10008
- const { cmdHealth } = await import("./health-LTDSTNOV.js");
10323
+ const { cmdHealth } = await import("./health-MB63O56B.js");
10009
10324
  await cmdHealth(projectRoot, {
10010
10325
  browser: runBrowser,
10011
10326
  browserBaseUrl: baseUrl,
@@ -10040,13 +10355,43 @@ async function cmdAdoptWorkflow(args) {
10040
10355
  }
10041
10356
  async function cmdVerifyWorkflow(args) {
10042
10357
  const { flags } = parseLooseArgs(args);
10358
+ const projectArg = flagString(flags, "project");
10359
+ if (!ensureAllowedFlags(
10360
+ flags,
10361
+ [
10362
+ "project",
10363
+ "workspace",
10364
+ "changed",
10365
+ "since",
10366
+ "json",
10367
+ "markdown",
10368
+ "format",
10369
+ "output",
10370
+ "ci",
10371
+ "fail-on",
10372
+ "prompt",
10373
+ "brownfield",
10374
+ "local-patterns",
10375
+ "evidence",
10376
+ "browser",
10377
+ "require-browser",
10378
+ "base-url",
10379
+ "design-tokens",
10380
+ "save-baseline",
10381
+ "since-baseline",
10382
+ "baseline"
10383
+ ],
10384
+ "verify"
10385
+ )) {
10386
+ return;
10387
+ }
10043
10388
  const workspaceMode = flagBoolean(flags, "workspace");
10044
10389
  if (args[1] === "init-ci") {
10045
10390
  await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
10046
10391
  return;
10047
10392
  }
10048
10393
  if (workspaceMode) {
10049
- const { cmdWorkspace } = await import("./workspace-53EIHUXB.js");
10394
+ const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
10050
10395
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
10051
10396
  return;
10052
10397
  }
@@ -10089,7 +10434,7 @@ async function cmdVerifyWorkflow(args) {
10089
10434
  process.exitCode = void 0;
10090
10435
  }
10091
10436
  }
10092
- const { cmdHealth, parseHealthArgs } = await import("./health-LTDSTNOV.js");
10437
+ const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
10093
10438
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10094
10439
  if (localPatterns) {
10095
10440
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10097,7 +10442,7 @@ async function cmdVerifyWorkflow(args) {
10097
10442
  if (!quietOutput) {
10098
10443
  console.log("");
10099
10444
  console.log(
10100
- `${YELLOW10}Local pattern pack missing.${RESET16} Run ${cyan3("decantr codify --from-audit")}, review the proposal, then run ${cyan3("decantr codify --accept")}.`
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))}.`
10101
10446
  );
10102
10447
  }
10103
10448
  process.exitCode = process.exitCode || 1;
@@ -10159,7 +10504,7 @@ async function cmdTaskWorkflow(args) {
10159
10504
  const routeInput = positional[0];
10160
10505
  if (!routeInput) {
10161
10506
  console.error(
10162
- error3(
10507
+ error2(
10163
10508
  'Usage: decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]'
10164
10509
  )
10165
10510
  );
@@ -10172,20 +10517,20 @@ async function cmdTaskWorkflow(args) {
10172
10517
  const essence = readJsonIfPresent(essencePath);
10173
10518
  if (!essence) {
10174
10519
  console.error(
10175
- error3("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10520
+ error2("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10176
10521
  );
10177
10522
  process.exitCode = 1;
10178
10523
  return;
10179
10524
  }
10180
10525
  if (!isV49(essence)) {
10181
- console.error(error3("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10526
+ console.error(error2("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10182
10527
  process.exitCode = 1;
10183
10528
  return;
10184
10529
  }
10185
10530
  const target = essence.blueprint.routes?.[route];
10186
10531
  if (!target) {
10187
10532
  const knownRoutes = Object.keys(essence.blueprint.routes ?? {}).sort();
10188
- console.error(error3(`Route not found in Decantr contract: ${route}`));
10533
+ console.error(error2(`Route not found in Decantr contract: ${route}`));
10189
10534
  console.error(dim3(`Known routes: ${knownRoutes.join(", ") || "none"}`));
10190
10535
  process.exitCode = 1;
10191
10536
  return;
@@ -10201,6 +10546,11 @@ async function cmdTaskWorkflow(args) {
10201
10546
  const localPatternPackPath = localPatternsPath(workspaceInfo.appRoot);
10202
10547
  const localRuleManifestPath = localRulesPath(workspaceInfo.appRoot);
10203
10548
  const localLaw = createLocalLawTaskSummary(workspaceInfo.appRoot);
10549
+ const displayedLocalLaw = {
10550
+ ...localLaw,
10551
+ patternsPath: localLaw.patternsPath ? displayProjectPath(workspaceInfo, localLaw.patternsPath) : null,
10552
+ rulesPath: localLaw.rulesPath ? displayProjectPath(workspaceInfo, localLaw.rulesPath) : null
10553
+ };
10204
10554
  const changedSince = flagString(flags, "since");
10205
10555
  const currentChangedFiles = changedFiles(workspaceInfo.appRoot, changedSince);
10206
10556
  const changedRoutes = routeImpacts(workspaceInfo.appRoot, currentChangedFiles);
@@ -10212,16 +10562,16 @@ async function cmdTaskWorkflow(args) {
10212
10562
  shell: page?.shell ?? section?.shell ?? null,
10213
10563
  patterns: page?.layout?.map(extractPatternName) ?? [],
10214
10564
  read: [
10215
- pagePack ? join31(".decantr/context", pagePack.markdown) : null,
10216
- sectionPack ? join31(".decantr/context", sectionPack.markdown) : null,
10217
- manifest?.scaffold?.markdown ? join31(".decantr/context", manifest.scaffold.markdown) : null,
10218
- ".decantr/context/scaffold.md",
10219
- "DECANTR.md",
10220
- existsSync29(localPatternPackPath) ? ".decantr/local-patterns.json" : null,
10221
- existsSync29(localRuleManifestPath) ? ".decantr/rules.json" : null
10565
+ pagePack ? displayProjectPath(workspaceInfo, join31(".decantr/context", pagePack.markdown)) : null,
10566
+ sectionPack ? displayProjectPath(workspaceInfo, join31(".decantr/context", sectionPack.markdown)) : null,
10567
+ manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join31(".decantr/context", manifest.scaffold.markdown)) : null,
10568
+ displayProjectPath(workspaceInfo, ".decantr/context/scaffold.md"),
10569
+ displayProjectPath(workspaceInfo, "DECANTR.md"),
10570
+ existsSync29(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
10571
+ existsSync29(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null
10222
10572
  ].filter(Boolean),
10223
- screenshot: screenshot ?? null,
10224
- localLaw,
10573
+ screenshot: screenshot?.startsWith(".decantr/") ? displayProjectPath(workspaceInfo, screenshot) : screenshot ?? null,
10574
+ localLaw: displayedLocalLaw,
10225
10575
  changedFiles: currentChangedFiles,
10226
10576
  changedRoutes,
10227
10577
  verifyCommand: withProject("decantr verify --brownfield --local-patterns", projectArg)
@@ -10290,12 +10640,20 @@ async function cmdTaskWorkflow(args) {
10290
10640
  }
10291
10641
  async function cmdCodifyWorkflow(args) {
10292
10642
  const { flags } = parseLooseArgs(args);
10643
+ const projectArg = flagString(flags, "project");
10644
+ if (!ensureAllowedFlags(
10645
+ flags,
10646
+ ["project", "from-audit", "discover-local-patterns", "codify-local-patterns", "accept"],
10647
+ "codify"
10648
+ )) {
10649
+ return;
10650
+ }
10293
10651
  const workspaceInfo = resolveWorkflowProject(flags, "codify");
10294
10652
  if (!workspaceInfo) return;
10295
10653
  if (flagBoolean(flags, "accept")) {
10296
10654
  if (!existsSync29(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync29(localRulesProposalPath(workspaceInfo.appRoot))) {
10297
10655
  console.error(
10298
- error3(
10656
+ error2(
10299
10657
  "No local law proposal found. Run `decantr codify --from-audit` or `decantr codify` first."
10300
10658
  )
10301
10659
  );
@@ -10309,7 +10667,11 @@ async function cmdCodifyWorkflow(args) {
10309
10667
  if (result2.rulesAcceptedPath) {
10310
10668
  console.log(success3(`Accepted local rule manifest: ${result2.rulesAcceptedPath}`));
10311
10669
  }
10312
- console.log(dim3("Run `decantr verify --brownfield --local-patterns` after project edits."));
10670
+ console.log(
10671
+ dim3(
10672
+ `Run \`${withProject("decantr verify --brownfield --local-patterns", projectArg)}\` after project edits.`
10673
+ )
10674
+ );
10313
10675
  return;
10314
10676
  }
10315
10677
  const detected = detectProject(workspaceInfo.appRoot);
@@ -10333,7 +10695,7 @@ async function cmdCodifyWorkflow(args) {
10333
10695
  }
10334
10696
  console.log(
10335
10697
  dim3(
10336
- "Review both files, add real component paths/token recipes, then run `decantr codify --accept`."
10698
+ `Review both files, add real component paths/token recipes, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
10337
10699
  )
10338
10700
  );
10339
10701
  }
@@ -10348,10 +10710,12 @@ async function cmdContentWorkflow(args) {
10348
10710
  return;
10349
10711
  }
10350
10712
  if (subcommand === "create") {
10713
+ const { flags } = parseLooseArgs(args);
10714
+ if (!ensureAllowedFlags(flags, [], "content create")) return;
10351
10715
  const type = args[2];
10352
10716
  const name = args[3];
10353
10717
  if (!type || !name) {
10354
- console.error(error3("Usage: decantr content create <type> <name>"));
10718
+ console.error(error2("Usage: decantr content create <type> <name>"));
10355
10719
  process.exitCode = 1;
10356
10720
  return;
10357
10721
  }
@@ -10359,17 +10723,19 @@ async function cmdContentWorkflow(args) {
10359
10723
  return;
10360
10724
  }
10361
10725
  if (subcommand === "publish") {
10726
+ const { flags } = parseLooseArgs(args);
10727
+ if (!ensureAllowedFlags(flags, [], "content publish")) return;
10362
10728
  const type = args[2];
10363
10729
  const name = args[3];
10364
10730
  if (!type || !name) {
10365
- console.error(error3("Usage: decantr content publish <type> <name>"));
10731
+ console.error(error2("Usage: decantr content publish <type> <name>"));
10366
10732
  process.exitCode = 1;
10367
10733
  return;
10368
10734
  }
10369
10735
  await cmdPublish(type, name);
10370
10736
  return;
10371
10737
  }
10372
- console.error(error3("Usage: decantr content <check|create|publish>"));
10738
+ console.error(error2("Usage: decantr content <check|create|publish>"));
10373
10739
  process.exitCode = 1;
10374
10740
  }
10375
10741
  function cmdHelp() {
@@ -10905,10 +11271,10 @@ async function main() {
10905
11271
  }
10906
11272
  }
10907
11273
  }
10908
- console.error(error3("Could not resolve @decantr/cli version from package.json."));
11274
+ console.error(error2("Could not resolve @decantr/cli version from package.json."));
10909
11275
  process.exitCode = 1;
10910
11276
  } catch (e) {
10911
- console.error(error3(`Failed to read CLI version: ${e.message}`));
11277
+ console.error(error2(`Failed to read CLI version: ${e.message}`));
10912
11278
  process.exitCode = 1;
10913
11279
  }
10914
11280
  return;
@@ -10953,7 +11319,7 @@ async function main() {
10953
11319
  const newName = args[1];
10954
11320
  if (!newName) {
10955
11321
  console.error(
10956
- error3("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
11322
+ error2("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
10957
11323
  );
10958
11324
  process.exitCode = 1;
10959
11325
  break;
@@ -11025,7 +11391,10 @@ async function main() {
11025
11391
  break;
11026
11392
  }
11027
11393
  case "status": {
11028
- await cmdStatus();
11394
+ const { flags } = parseLooseArgs(args);
11395
+ const workspaceInfo = resolveWorkflowProject(flags, "status");
11396
+ if (!workspaceInfo) break;
11397
+ await cmdStatus(workspaceInfo.appRoot);
11029
11398
  break;
11030
11399
  }
11031
11400
  case "sync": {
@@ -11034,8 +11403,11 @@ async function main() {
11034
11403
  }
11035
11404
  case "upgrade": {
11036
11405
  const { cmdUpgrade } = await import("./upgrade-VON7Y3LG.js");
11406
+ const { flags } = parseLooseArgs(args);
11407
+ const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
11408
+ if (!workspaceInfo) break;
11037
11409
  const applyFlag = args.includes("--apply");
11038
- await cmdUpgrade(process.cwd(), { apply: applyFlag });
11410
+ await cmdUpgrade(workspaceInfo.appRoot, { apply: applyFlag });
11039
11411
  break;
11040
11412
  }
11041
11413
  case "check":
@@ -11051,7 +11423,10 @@ async function main() {
11051
11423
  if (!workspaceInfo) break;
11052
11424
  const telemetryFlag = args.includes("--telemetry");
11053
11425
  const brownfieldFlag = args.includes("--brownfield");
11054
- await cmdHeal(workspaceInfo.appRoot, { telemetry: telemetryFlag, brownfield: brownfieldFlag });
11426
+ await cmdHeal(workspaceInfo.appRoot, {
11427
+ telemetry: telemetryFlag,
11428
+ brownfield: brownfieldFlag
11429
+ });
11055
11430
  break;
11056
11431
  }
11057
11432
  case "health": {
@@ -11060,10 +11435,17 @@ async function main() {
11060
11435
  cmdHealthHelp();
11061
11436
  break;
11062
11437
  }
11063
- const { cmdHealth, parseHealthArgs } = await import("./health-LTDSTNOV.js");
11064
- await cmdHealth(process.cwd(), parseHealthArgs(args));
11438
+ if (args[1] === "init-ci") {
11439
+ await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
11440
+ break;
11441
+ }
11442
+ const { flags } = parseLooseArgs(args);
11443
+ const workspaceInfo = resolveWorkflowProject(flags, "health");
11444
+ if (!workspaceInfo) break;
11445
+ const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
11446
+ await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
11065
11447
  } catch (e) {
11066
- console.error(error3(e.message));
11448
+ console.error(error2(e.message));
11067
11449
  process.exitCode = 1;
11068
11450
  }
11069
11451
  break;
@@ -11077,7 +11459,7 @@ async function main() {
11077
11459
  const { cmdContentHealth, parseContentHealthArgs } = await import("./content-health-4KP2EGTI.js");
11078
11460
  await cmdContentHealth(process.cwd(), parseContentHealthArgs(args));
11079
11461
  } catch (e) {
11080
- console.error(error3(e.message));
11462
+ console.error(error2(e.message));
11081
11463
  process.exitCode = 1;
11082
11464
  }
11083
11465
  break;
@@ -11088,10 +11470,10 @@ async function main() {
11088
11470
  cmdStudioHelp();
11089
11471
  break;
11090
11472
  }
11091
- const { cmdStudio, parseStudioArgs } = await import("./studio-7E2LJS3A.js");
11473
+ const { cmdStudio, parseStudioArgs } = await import("./studio-6QGXJBVH.js");
11092
11474
  await cmdStudio(process.cwd(), parseStudioArgs(args));
11093
11475
  } catch (e) {
11094
- console.error(error3(e.message));
11476
+ console.error(error2(e.message));
11095
11477
  process.exitCode = 1;
11096
11478
  }
11097
11479
  break;
@@ -11102,10 +11484,10 @@ async function main() {
11102
11484
  cmdWorkspaceHelp();
11103
11485
  break;
11104
11486
  }
11105
- const { cmdWorkspace } = await import("./workspace-53EIHUXB.js");
11487
+ const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
11106
11488
  await cmdWorkspace(process.cwd(), args);
11107
11489
  } catch (e) {
11108
- console.error(error3(e.message));
11490
+ console.error(error2(e.message));
11109
11491
  process.exitCode = 1;
11110
11492
  }
11111
11493
  break;
@@ -11128,7 +11510,7 @@ async function main() {
11128
11510
  if (result.success) {
11129
11511
  console.log(success3(clearFlag ? "Drift log cleared." : "Entries resolved."));
11130
11512
  } else {
11131
- console.error(error3(result.error || "Failed"));
11513
+ console.error(error2(result.error || "Failed"));
11132
11514
  process.exitCode = 1;
11133
11515
  }
11134
11516
  } else {
@@ -11144,7 +11526,7 @@ async function main() {
11144
11526
  const query = args[1];
11145
11527
  if (!query) {
11146
11528
  console.error(
11147
- error3(
11529
+ error2(
11148
11530
  "Usage: decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11149
11531
  )
11150
11532
  );
@@ -11162,7 +11544,7 @@ async function main() {
11162
11544
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11163
11545
  if (rawBlueprintSet && !blueprintSet) {
11164
11546
  console.error(
11165
- error3(
11547
+ error2(
11166
11548
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11167
11549
  )
11168
11550
  );
@@ -11171,7 +11553,7 @@ async function main() {
11171
11553
  }
11172
11554
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11173
11555
  console.error(
11174
- error3(
11556
+ error2(
11175
11557
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11176
11558
  )
11177
11559
  );
@@ -11183,31 +11565,51 @@ async function main() {
11183
11565
  break;
11184
11566
  }
11185
11567
  case "suggest": {
11186
- const query = args[1];
11568
+ const { flags, positional } = parseLooseArgs(args);
11569
+ if (!ensureAllowedFlags(flags, ["type", "route", "file", "from-code", "project"], "suggest")) {
11570
+ break;
11571
+ }
11572
+ const projectArg = flagString(flags, "project");
11573
+ const route = flagString(flags, "route");
11574
+ let file = flagString(flags, "file");
11575
+ const normalizedProject = normalizedProjectPath(projectArg);
11576
+ if (file && normalizedProject && normalizedProjectPath(file)?.startsWith(`${normalizedProject}/`)) {
11577
+ file = normalizedProjectPath(file)?.slice(normalizedProject.length + 1);
11578
+ }
11579
+ const fromCode = flagBoolean(flags, "from-code");
11580
+ let query = positional.join(" ").trim();
11581
+ if (!query && (route || file || fromCode)) {
11582
+ query = [
11583
+ route ? `route ${route}` : null,
11584
+ file ? `file ${basename3(file)}` : null,
11585
+ fromCode ? "source code patterns" : null
11586
+ ].filter((entry) => Boolean(entry)).join(" ");
11587
+ }
11187
11588
  if (!query) {
11188
11589
  console.error(
11189
- error3(
11190
- "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code]"
11590
+ error2(
11591
+ "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code] [--project <path>]"
11191
11592
  )
11192
11593
  );
11193
11594
  process.exitCode = 1;
11194
11595
  return;
11195
11596
  }
11196
- const typeIdx = args.indexOf("--type");
11197
- const type = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
11198
- const routeIdx = args.indexOf("--route");
11199
- const route = routeIdx !== -1 ? args[routeIdx + 1] : void 0;
11200
- const fileIdx = args.indexOf("--file");
11201
- const file = fileIdx !== -1 ? args[fileIdx + 1] : void 0;
11202
- const fromCode = args.includes("--from-code");
11203
- await cmdSuggest(query, { type, route, file, fromCode });
11597
+ const workspaceInfo = projectArg ? resolveWorkflowProject(flags, "suggest") : null;
11598
+ if (projectArg && !workspaceInfo) break;
11599
+ await cmdSuggest(query, {
11600
+ type: flagString(flags, "type"),
11601
+ route,
11602
+ file,
11603
+ fromCode,
11604
+ projectRoot: workspaceInfo?.appRoot
11605
+ });
11204
11606
  break;
11205
11607
  }
11206
11608
  case "get": {
11207
11609
  const type = args[1];
11208
11610
  const id = args[2];
11209
11611
  if (!type || !id) {
11210
- console.error(error3("Usage: decantr get <type> <id>"));
11612
+ console.error(error2("Usage: decantr get <type> <id>"));
11211
11613
  process.exitCode = 1;
11212
11614
  return;
11213
11615
  }
@@ -11218,7 +11620,7 @@ async function main() {
11218
11620
  const type = args[1];
11219
11621
  if (!type) {
11220
11622
  console.error(
11221
- error3(
11623
+ error2(
11222
11624
  "Usage: decantr list <type> [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11223
11625
  )
11224
11626
  );
@@ -11234,7 +11636,7 @@ async function main() {
11234
11636
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11235
11637
  if (rawBlueprintSet && !blueprintSet) {
11236
11638
  console.error(
11237
- error3(
11639
+ error2(
11238
11640
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11239
11641
  )
11240
11642
  );
@@ -11243,7 +11645,7 @@ async function main() {
11243
11645
  }
11244
11646
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11245
11647
  console.error(
11246
- error3(
11648
+ error2(
11247
11649
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11248
11650
  )
11249
11651
  );
@@ -11263,7 +11665,7 @@ async function main() {
11263
11665
  break;
11264
11666
  }
11265
11667
  if (requestedView && !["manifest", "shortlist", "verification"].includes(requestedView)) {
11266
- console.error(error3("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11668
+ console.error(error2("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11267
11669
  process.exitCode = 1;
11268
11670
  break;
11269
11671
  }
@@ -11275,7 +11677,10 @@ async function main() {
11275
11677
  break;
11276
11678
  }
11277
11679
  case "theme": {
11278
- await cmdTheme(args.slice(1));
11680
+ const { flags } = parseLooseArgs(args);
11681
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "theme") : null;
11682
+ if (flagString(flags, "project") && !workspaceInfo) break;
11683
+ await cmdTheme(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11279
11684
  break;
11280
11685
  }
11281
11686
  case "login": {
@@ -11309,14 +11714,19 @@ async function main() {
11309
11714
  break;
11310
11715
  }
11311
11716
  case "telemetry": {
11312
- await cmdTelemetry(args.slice(1), process.cwd());
11717
+ const { flags } = parseLooseArgs(args);
11718
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "telemetry") : null;
11719
+ if (flagString(flags, "project") && !workspaceInfo) break;
11720
+ await cmdTelemetry(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11313
11721
  break;
11314
11722
  }
11315
11723
  case "create": {
11724
+ const { flags } = parseLooseArgs(args);
11725
+ if (!ensureAllowedFlags(flags, [], "create")) break;
11316
11726
  const type = args[1];
11317
11727
  const name = args[2];
11318
11728
  if (!type || !name) {
11319
- console.error(error3("Usage: decantr create <type> <name>"));
11729
+ console.error(error2("Usage: decantr create <type> <name>"));
11320
11730
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11321
11731
  process.exitCode = 1;
11322
11732
  break;
@@ -11325,10 +11735,12 @@ async function main() {
11325
11735
  break;
11326
11736
  }
11327
11737
  case "publish": {
11738
+ const { flags } = parseLooseArgs(args);
11739
+ if (!ensureAllowedFlags(flags, [], "publish")) break;
11328
11740
  const type = args[1];
11329
11741
  const name = args[2];
11330
11742
  if (!type || !name) {
11331
- console.error(error3("Usage: decantr publish <type> <name>"));
11743
+ console.error(error2("Usage: decantr publish <type> <name>"));
11332
11744
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11333
11745
  process.exitCode = 1;
11334
11746
  break;
@@ -11345,7 +11757,8 @@ async function main() {
11345
11757
  offline: refreshOffline,
11346
11758
  check: args.includes("--check"),
11347
11759
  listChanges: args.includes("--list-changes"),
11348
- json: args.includes("--json")
11760
+ json: args.includes("--json"),
11761
+ displayRoot: workspaceInfo.cwd
11349
11762
  });
11350
11763
  break;
11351
11764
  }
@@ -11380,7 +11793,7 @@ async function main() {
11380
11793
  let id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
11381
11794
  if (!packType || !["manifest", "scaffold", "review", "section", "page", "mutation"].includes(packType)) {
11382
11795
  console.error(
11383
- `${RED13}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11796
+ `${RED12}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11384
11797
  );
11385
11798
  process.exitCode = 1;
11386
11799
  break;
@@ -11412,7 +11825,7 @@ async function main() {
11412
11825
  const sourcePath = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
11413
11826
  if (!sourcePath) {
11414
11827
  console.error(
11415
- `${RED13}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11828
+ `${RED12}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11416
11829
  );
11417
11830
  process.exitCode = 1;
11418
11831
  break;
@@ -11437,16 +11850,20 @@ async function main() {
11437
11850
  await printHostedProjectAudit(namespace, jsonOutput, essencePath, distPath, sourcesPath);
11438
11851
  } else {
11439
11852
  console.error(
11440
- `${RED13}Usage: decantr registry mirror [--type <type>] | decantr registry summary [--namespace <namespace>] [--json] | decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context] | decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context] | decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>] | decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]${RESET16}`
11853
+ `${RED12}Usage: decantr registry mirror [--type <type>] | decantr registry summary [--namespace <namespace>] [--json] | decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context] | decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context] | decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>] | decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]${RESET16}`
11441
11854
  );
11442
11855
  process.exitCode = 1;
11443
11856
  }
11444
11857
  break;
11445
11858
  }
11446
11859
  case "add": {
11860
+ const { flags } = parseLooseArgs(args);
11861
+ if (!ensureAllowedFlags(flags, ["project", "route", "section"], "add")) break;
11862
+ const workspaceInfo = resolveWorkflowProject(flags, "add");
11863
+ if (!workspaceInfo) break;
11447
11864
  const subcommand = args[1];
11448
11865
  if (!subcommand) {
11449
- console.error(error3("Usage: decantr add <section|page|feature> <target>"));
11866
+ console.error(error2("Usage: decantr add <section|page|feature> <target>"));
11450
11867
  process.exitCode = 1;
11451
11868
  break;
11452
11869
  }
@@ -11454,45 +11871,49 @@ async function main() {
11454
11871
  case "section": {
11455
11872
  const id = args[2];
11456
11873
  if (!id) {
11457
- console.error(error3("Usage: decantr add section <archetypeId>"));
11874
+ console.error(error2("Usage: decantr add section <archetypeId>"));
11458
11875
  process.exitCode = 1;
11459
11876
  break;
11460
11877
  }
11461
- await cmdAddSection(id, args, process.cwd());
11878
+ await cmdAddSection(id, args, workspaceInfo.appRoot);
11462
11879
  break;
11463
11880
  }
11464
11881
  case "page": {
11465
11882
  const pagePath = args[2];
11466
11883
  if (!pagePath) {
11467
- console.error(error3("Usage: decantr add page <section>/<page>"));
11884
+ console.error(error2("Usage: decantr add page <section>/<page>"));
11468
11885
  process.exitCode = 1;
11469
11886
  break;
11470
11887
  }
11471
- await cmdAddPage(pagePath, args, process.cwd());
11888
+ await cmdAddPage(pagePath, args, workspaceInfo.appRoot);
11472
11889
  break;
11473
11890
  }
11474
11891
  case "feature": {
11475
11892
  const feature = args[2];
11476
11893
  if (!feature) {
11477
- console.error(error3("Usage: decantr add feature <feature> [--section <id>]"));
11894
+ console.error(error2("Usage: decantr add feature <feature> [--section <id>]"));
11478
11895
  process.exitCode = 1;
11479
11896
  break;
11480
11897
  }
11481
- await cmdAddFeature(feature, args, process.cwd());
11898
+ await cmdAddFeature(feature, args, workspaceInfo.appRoot);
11482
11899
  break;
11483
11900
  }
11484
11901
  default:
11485
11902
  console.error(
11486
- error3(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11903
+ error2(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11487
11904
  );
11488
11905
  process.exitCode = 1;
11489
11906
  }
11490
11907
  break;
11491
11908
  }
11492
11909
  case "remove": {
11910
+ const { flags } = parseLooseArgs(args);
11911
+ if (!ensureAllowedFlags(flags, ["project", "section"], "remove")) break;
11912
+ const workspaceInfo = resolveWorkflowProject(flags, "remove");
11913
+ if (!workspaceInfo) break;
11493
11914
  const subcommand = args[1];
11494
11915
  if (!subcommand) {
11495
- console.error(error3("Usage: decantr remove <section|page|feature> <target>"));
11916
+ console.error(error2("Usage: decantr remove <section|page|feature> <target>"));
11496
11917
  process.exitCode = 1;
11497
11918
  break;
11498
11919
  }
@@ -11500,56 +11921,54 @@ async function main() {
11500
11921
  case "section": {
11501
11922
  const id = args[2];
11502
11923
  if (!id) {
11503
- console.error(error3("Usage: decantr remove section <sectionId>"));
11924
+ console.error(error2("Usage: decantr remove section <sectionId>"));
11504
11925
  process.exitCode = 1;
11505
11926
  break;
11506
11927
  }
11507
- await cmdRemoveSection(id, args, process.cwd());
11928
+ await cmdRemoveSection(id, args, workspaceInfo.appRoot);
11508
11929
  break;
11509
11930
  }
11510
11931
  case "page": {
11511
11932
  const pagePath = args[2];
11512
11933
  if (!pagePath) {
11513
- console.error(error3("Usage: decantr remove page <section>/<page>"));
11934
+ console.error(error2("Usage: decantr remove page <section>/<page>"));
11514
11935
  process.exitCode = 1;
11515
11936
  break;
11516
11937
  }
11517
- await cmdRemovePage(pagePath, args, process.cwd());
11938
+ await cmdRemovePage(pagePath, args, workspaceInfo.appRoot);
11518
11939
  break;
11519
11940
  }
11520
11941
  case "feature": {
11521
11942
  const feature = args[2];
11522
11943
  if (!feature) {
11523
- console.error(error3("Usage: decantr remove feature <feature> [--section <id>]"));
11944
+ console.error(error2("Usage: decantr remove feature <feature> [--section <id>]"));
11524
11945
  process.exitCode = 1;
11525
11946
  break;
11526
11947
  }
11527
- await cmdRemoveFeature(feature, args, process.cwd());
11948
+ await cmdRemoveFeature(feature, args, workspaceInfo.appRoot);
11528
11949
  break;
11529
11950
  }
11530
11951
  default:
11531
11952
  console.error(
11532
- error3(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11953
+ error2(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11533
11954
  );
11534
11955
  process.exitCode = 1;
11535
11956
  }
11536
11957
  break;
11537
11958
  }
11538
11959
  case "analyze": {
11539
- let projectArg;
11540
- for (let i = 1; i < args.length; i++) {
11541
- if (args[i].startsWith("--project=")) {
11542
- projectArg = args[i].split("=")[1];
11543
- } else if (args[i] === "--project" && args[i + 1]) {
11544
- projectArg = args[++i];
11545
- }
11546
- }
11547
- const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
11548
- if (workspaceInfo.requiresProjectSelection) {
11549
- printWorkspaceProjectSelection(workspaceInfo, "analyze");
11550
- process.exitCode = 1;
11960
+ const { flags } = parseLooseArgs(args);
11961
+ if (!ensureAllowedFlags(
11962
+ flags,
11963
+ ["project", "force-package", "allow-package", "force"],
11964
+ "analyze"
11965
+ )) {
11551
11966
  break;
11552
11967
  }
11968
+ const workspaceInfo = resolveWorkflowProject(flags, "analyze", {
11969
+ requireAppCandidate: true
11970
+ });
11971
+ if (!workspaceInfo) break;
11553
11972
  await cmdAnalyze(workspaceInfo.appRoot, workspaceInfo);
11554
11973
  break;
11555
11974
  }
@@ -11560,24 +11979,14 @@ async function main() {
11560
11979
  break;
11561
11980
  }
11562
11981
  if (subcommand !== "apply" && subcommand !== "preview") {
11563
- console.error(error3("Usage: decantr rules <preview|apply> [--project=<path>]"));
11564
- process.exitCode = 1;
11565
- break;
11566
- }
11567
- let projectArg;
11568
- for (let i = 2; i < args.length; i++) {
11569
- if (args[i].startsWith("--project=")) {
11570
- projectArg = args[i].split("=")[1];
11571
- } else if (args[i] === "--project" && args[i + 1]) {
11572
- projectArg = args[++i];
11573
- }
11574
- }
11575
- const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
11576
- if (workspaceInfo.requiresProjectSelection) {
11577
- printWorkspaceProjectSelection(workspaceInfo, "rules");
11982
+ console.error(error2("Usage: decantr rules <preview|apply> [--project=<path>]"));
11578
11983
  process.exitCode = 1;
11579
11984
  break;
11580
11985
  }
11986
+ const { flags } = parseLooseArgs(args);
11987
+ if (!ensureAllowedFlags(flags, ["project"], "rules")) break;
11988
+ const workspaceInfo = resolveWorkflowProject(flags, "rules");
11989
+ if (!workspaceInfo) break;
11581
11990
  const detected = detectProject(workspaceInfo.appRoot);
11582
11991
  if (subcommand === "preview") {
11583
11992
  console.log(
@@ -11598,24 +12007,18 @@ async function main() {
11598
12007
  break;
11599
12008
  }
11600
12009
  case "magic": {
11601
- const magicFlags = {};
11602
- const promptParts = [];
11603
- for (let i = 1; i < args.length; i++) {
11604
- if (args[i] === "--dry-run") {
11605
- magicFlags.dryRun = true;
11606
- } else if (args[i] === "--offline") {
11607
- magicFlags.offline = true;
11608
- } else if (args[i].startsWith("--registry=")) {
11609
- magicFlags.registry = args[i].split("=")[1];
11610
- } else if (args[i].startsWith("--registry") && args[i + 1]) {
11611
- magicFlags.registry = args[++i];
11612
- } else {
11613
- promptParts.push(args[i]);
11614
- }
12010
+ const { flags, positional } = parseLooseArgs(args);
12011
+ if (!ensureAllowedFlags(flags, ["dry-run", "offline", "registry", "project"], "magic")) {
12012
+ break;
11615
12013
  }
11616
- const magicPrompt = promptParts.join(" ").trim();
12014
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "magic") : null;
12015
+ if (flagString(flags, "project") && !workspaceInfo) break;
12016
+ const projectArg = flagString(flags, "project");
12017
+ const magicPrompt = positional.join(" ").trim();
11617
12018
  if (!magicPrompt) {
11618
- console.error(error3("Usage: decantr magic <prompt> [--dry-run] [--offline]"));
12019
+ console.error(
12020
+ error2("Usage: decantr magic <prompt> [--dry-run] [--offline] [--project <path>]")
12021
+ );
11619
12022
  console.error("");
11620
12023
  console.error(" Example:");
11621
12024
  console.error(
@@ -11624,38 +12027,34 @@ async function main() {
11624
12027
  process.exitCode = 1;
11625
12028
  break;
11626
12029
  }
11627
- await cmdMagic(magicPrompt, process.cwd(), {
11628
- dryRun: magicFlags.dryRun,
11629
- offline: magicFlags.offline,
11630
- registry: magicFlags.registry
12030
+ await cmdMagic(magicPrompt, workspaceInfo?.appRoot ?? process.cwd(), {
12031
+ dryRun: flagBoolean(flags, "dry-run"),
12032
+ offline: flagBoolean(flags, "offline"),
12033
+ registry: flagString(flags, "registry"),
12034
+ projectLabel: projectArg
11631
12035
  });
11632
12036
  break;
11633
12037
  }
11634
12038
  case "export": {
11635
- let exportTarget;
11636
- let exportOutput;
11637
- for (let i = 1; i < args.length; i++) {
11638
- if (args[i] === "--to" && args[i + 1]) {
11639
- exportTarget = args[++i];
11640
- } else if (args[i].startsWith("--to=")) {
11641
- exportTarget = args[i].split("=")[1];
11642
- } else if (args[i] === "--output" && args[i + 1]) {
11643
- exportOutput = args[++i];
11644
- } else if (args[i].startsWith("--output=")) {
11645
- exportOutput = args[i].split("=")[1];
11646
- }
11647
- }
12039
+ const { flags } = parseLooseArgs(args);
12040
+ if (!ensureAllowedFlags(flags, ["to", "output", "project"], "export")) break;
12041
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "export") : null;
12042
+ if (flagString(flags, "project") && !workspaceInfo) break;
12043
+ const exportTarget = flagString(flags, "to");
12044
+ const exportOutput = flagString(flags, "output");
11648
12045
  const validTargets = ["shadcn", "tailwind", "css-vars", "figma-tokens"];
11649
12046
  if (!exportTarget || !validTargets.includes(exportTarget)) {
11650
- console.error(error3(`Usage: decantr export --to <${validTargets.join("|")}>`));
12047
+ console.error(error2(`Usage: decantr export --to <${validTargets.join("|")}>`));
11651
12048
  process.exitCode = 1;
11652
12049
  break;
11653
12050
  }
11654
- await cmdExport(exportTarget, process.cwd(), { output: exportOutput });
12051
+ await cmdExport(exportTarget, workspaceInfo?.appRoot ?? process.cwd(), {
12052
+ output: exportOutput
12053
+ });
11655
12054
  break;
11656
12055
  }
11657
12056
  default:
11658
- console.error(error3(`Unknown command: ${command}`));
12057
+ console.error(error2(`Unknown command: ${command}`));
11659
12058
  cmdHelp();
11660
12059
  process.exitCode = 1;
11661
12060
  }
@@ -11670,7 +12069,7 @@ main().then(async () => {
11670
12069
  success: !process.exitCode || process.exitCode === 0
11671
12070
  });
11672
12071
  }).catch(async (e) => {
11673
- console.error(error3(e.message));
12072
+ console.error(error2(e.message));
11674
12073
  if (e.stack) console.error(e.stack);
11675
12074
  process.exitCode = 1;
11676
12075
  await sendCliCommandTelemetry({