@decantr/cli 2.9.2 → 2.9.4

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-VCUFZB45.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-FACL3NXU.js";
33
33
  import {
34
34
  buildGuardRegistryContext,
35
35
  createDoctrineMap,
@@ -46,11 +46,11 @@ import {
46
46
  sendCliCommandTelemetry,
47
47
  sendNewProjectCompletedTelemetry,
48
48
  writeDoctrineMap
49
- } from "./chunk-34TZXWIF.js";
49
+ } from "./chunk-WONPNSSI.js";
50
50
 
51
51
  // src/index.ts
52
52
  import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync9, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "fs";
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,34 @@ 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 readAdoptionMode(projectRoot) {
4686
+ const projectJsonPath = join19(projectRoot, ".decantr", "project.json");
4687
+ if (!existsSync17(projectJsonPath)) return null;
4688
+ try {
4689
+ const parsed = JSON.parse(readFileSync14(projectJsonPath, "utf-8"));
4690
+ return typeof parsed.initialized?.adoptionMode === "string" ? parsed.initialized.adoptionMode : null;
4691
+ } catch {
4692
+ return null;
4693
+ }
4694
+ }
4695
+ function resolveOutputPath(projectRoot, output, fallback) {
4696
+ if (!output) return fallback;
4697
+ return isAbsolute(output) ? output : join19(projectRoot, output);
4698
+ }
4599
4699
  var SHADCN_MAP = {
4600
4700
  "--d-bg": "--background",
4601
4701
  "--d-text": "--foreground",
@@ -4744,9 +4844,7 @@ function generateFigmaTokens(tokens) {
4744
4844
  const out = {};
4745
4845
  for (const [key, value] of tokens) {
4746
4846
  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";
4847
+ 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
4848
  out[name] = {
4751
4849
  $type: type,
4752
4850
  $value: value,
@@ -4765,9 +4863,9 @@ async function cmdExport(target, projectRoot, options = {}) {
4765
4863
  return;
4766
4864
  }
4767
4865
  if (!existsSync17(tokensPath)) {
4768
- console.error(
4769
- `${RED4}No src/styles/tokens.css found. Run \`decantr refresh\` to generate tokens.${RESET5}`
4770
- );
4866
+ const adoptionMode = readAdoptionMode(projectRoot);
4867
+ const message = adoptionMode === "contract-only" ? `No src/styles/tokens.css found. This export reads Decantr CSS tokens, but this project is contract-only Brownfield and may intentionally use its own Tailwind/Sass token system. Export from the app's token source or adopt a style bridge before using \`decantr export --to ${target}\`.` : "No src/styles/tokens.css found. Run `decantr refresh` to generate tokens.";
4868
+ console.error(`${RED4}${message}${RESET5}`);
4771
4869
  process.exitCode = 1;
4772
4870
  return;
4773
4871
  }
@@ -4780,7 +4878,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4780
4878
  }
4781
4879
  switch (target) {
4782
4880
  case "shadcn": {
4783
- const cssOut = options.output ?? join19(projectRoot, "src", "styles", "shadcn-theme.css");
4881
+ const cssOut = resolveOutputPath(
4882
+ projectRoot,
4883
+ options.output,
4884
+ join19(projectRoot, "src", "styles", "shadcn-theme.css")
4885
+ );
4784
4886
  const jsonOut = join19(projectRoot, "components.json");
4785
4887
  ensureDir(cssOut);
4786
4888
  writeFileSync12(cssOut, generateShadcnCSS(tokens), "utf-8");
@@ -4791,7 +4893,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4791
4893
  break;
4792
4894
  }
4793
4895
  case "tailwind": {
4794
- const out = options.output ?? join19(projectRoot, "tailwind.decantr.config.ts");
4896
+ const out = resolveOutputPath(
4897
+ projectRoot,
4898
+ options.output,
4899
+ join19(projectRoot, "tailwind.decantr.config.ts")
4900
+ );
4795
4901
  ensureDir(out);
4796
4902
  writeFileSync12(out, generateTailwindConfig(tokens), "utf-8");
4797
4903
  console.log(`${GREEN5}Exported Tailwind config:${RESET5}`);
@@ -4799,7 +4905,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4799
4905
  break;
4800
4906
  }
4801
4907
  case "css-vars": {
4802
- const out = options.output ?? join19(projectRoot, "decantr-tokens.css");
4908
+ const out = resolveOutputPath(
4909
+ projectRoot,
4910
+ options.output,
4911
+ join19(projectRoot, "decantr-tokens.css")
4912
+ );
4803
4913
  ensureDir(out);
4804
4914
  writeFileSync12(out, generateCSSVars(tokens), "utf-8");
4805
4915
  console.log(`${GREEN5}Exported CSS variables:${RESET5}`);
@@ -4807,7 +4917,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4807
4917
  break;
4808
4918
  }
4809
4919
  case "figma-tokens": {
4810
- const out = options.output ?? join19(projectRoot, ".decantr", "design", "figma-tokens.json");
4920
+ const out = resolveOutputPath(
4921
+ projectRoot,
4922
+ options.output,
4923
+ join19(projectRoot, ".decantr", "design", "figma-tokens.json")
4924
+ );
4811
4925
  ensureDir(out);
4812
4926
  writeFileSync12(out, generateFigmaTokens(tokens), "utf-8");
4813
4927
  console.log(`${GREEN5}Exported Figma/Tokens Studio tokens:${RESET5}`);
@@ -4830,7 +4944,6 @@ import { join as join20 } from "path";
4830
4944
  var BOLD4 = "\x1B[1m";
4831
4945
  var DIM6 = "\x1B[2m";
4832
4946
  var RESET6 = "\x1B[0m";
4833
- var RED5 = "\x1B[31m";
4834
4947
  var GREEN6 = "\x1B[32m";
4835
4948
  var CYAN3 = "\x1B[36m";
4836
4949
  var YELLOW3 = "\x1B[33m";
@@ -4838,9 +4951,6 @@ var MAGENTA = "\x1B[35m";
4838
4951
  function success(text) {
4839
4952
  return `${GREEN6}${text}${RESET6}`;
4840
4953
  }
4841
- function error(text) {
4842
- return `${RED5}${text}${RESET6}`;
4843
- }
4844
4954
  function dim(text) {
4845
4955
  return `${DIM6}${text}${RESET6}`;
4846
4956
  }
@@ -5056,9 +5166,16 @@ async function cmdMagic(prompt, projectRoot, options) {
5056
5166
  console.log("");
5057
5167
  const essencePath = join20(projectRoot, "decantr.essence.json");
5058
5168
  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;
5169
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5170
+ console.log(`${YELLOW3} Decantr is already attached to this project.${RESET6}`);
5171
+ console.log(
5172
+ dim(" decantr magic is greenfield-first; use task-time context for existing apps.")
5173
+ );
5174
+ console.log("");
5175
+ console.log(`${BOLD4}Recommended next steps:${RESET6}`);
5176
+ console.log(` ${cyan(`decantr doctor${projectFlag}`)}`);
5177
+ console.log(` ${cyan(`decantr task <route> "${prompt}"${projectFlag}`)}`);
5178
+ console.log(` ${cyan(`decantr verify --brownfield --local-patterns${projectFlag}`)}`);
5062
5179
  return;
5063
5180
  }
5064
5181
  const detected = detectProject(projectRoot);
@@ -5073,8 +5190,9 @@ async function cmdMagic(prompt, projectRoot, options) {
5073
5190
  dim(" Running brownfield analysis instead so you can attach Decantr deliberately.\n")
5074
5191
  );
5075
5192
  await cmdAnalyze(projectRoot);
5193
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5076
5194
  console.log(
5077
- `${BOLD4}Recommended next step:${RESET6} ${cyan("decantr init --existing --accept-proposal")}`
5195
+ `${BOLD4}Recommended next step:${RESET6} ${cyan(`decantr init${projectFlag} --existing --accept-proposal`)}`
5078
5196
  );
5079
5197
  console.log("");
5080
5198
  return;
@@ -5400,7 +5518,7 @@ import {
5400
5518
  validateLegacyEssenceForMigration
5401
5519
  } from "@decantr/essence-spec";
5402
5520
  var GREEN7 = "\x1B[32m";
5403
- var RED6 = "\x1B[31m";
5521
+ var RED5 = "\x1B[31m";
5404
5522
  var YELLOW4 = "\x1B[33m";
5405
5523
  var RESET7 = "\x1B[0m";
5406
5524
  var DIM7 = "\x1B[2m";
@@ -5468,13 +5586,13 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5468
5586
  const inlineTarget = hasInlineTarget?.split("=")[1];
5469
5587
  const requestedTarget = inlineTarget ?? target;
5470
5588
  if (requestedTarget !== "v4") {
5471
- console.error(`${RED6}Usage: decantr migrate --to v4${RESET7}`);
5589
+ console.error(`${RED5}Usage: decantr migrate --to v4${RESET7}`);
5472
5590
  process.exitCode = 1;
5473
5591
  return;
5474
5592
  }
5475
5593
  const essencePath = join21(projectRoot, "decantr.essence.json");
5476
5594
  if (!existsSync19(essencePath)) {
5477
- console.error(`${RED6}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5595
+ console.error(`${RED5}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5478
5596
  process.exitCode = 1;
5479
5597
  return;
5480
5598
  }
@@ -5485,7 +5603,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5485
5603
  return;
5486
5604
  }
5487
5605
  if (!result.success) {
5488
- console.error(`${RED6}Migration failed: ${result.error}${RESET7}`);
5606
+ console.error(`${RED5}Migration failed: ${result.error}${RESET7}`);
5489
5607
  process.exitCode = 1;
5490
5608
  return;
5491
5609
  }
@@ -5565,7 +5683,7 @@ function seedOfflineRegistry(projectDir, workspaceRoot) {
5565
5683
  var BOLD5 = "\x1B[1m";
5566
5684
  var DIM8 = "\x1B[2m";
5567
5685
  var RESET8 = "\x1B[0m";
5568
- var RED7 = "\x1B[31m";
5686
+ var RED6 = "\x1B[31m";
5569
5687
  var GREEN8 = "\x1B[32m";
5570
5688
  var CYAN4 = "\x1B[36m";
5571
5689
  var YELLOW5 = "\x1B[33m";
@@ -5577,8 +5695,8 @@ ${BOLD5}${text}${RESET8}
5577
5695
  function success2(text) {
5578
5696
  return `${GREEN8}${text}${RESET8}`;
5579
5697
  }
5580
- function error2(text) {
5581
- return `${RED7}${text}${RESET8}`;
5698
+ function error(text) {
5699
+ return `${RED6}${text}${RESET8}`;
5582
5700
  }
5583
5701
  function dim2(text) {
5584
5702
  return `${DIM8}${text}${RESET8}`;
@@ -5685,13 +5803,13 @@ async function cmdNewProject(projectName, options) {
5685
5803
  const shouldBootstrapRuntime = Boolean(bootstrapAdapter && inferredAdoption === "decantr-css");
5686
5804
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
5687
5805
  console.error(
5688
- error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5806
+ error("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5689
5807
  );
5690
5808
  process.exitCode = 1;
5691
5809
  return;
5692
5810
  }
5693
5811
  if (existsSync21(projectDir)) {
5694
- console.error(error2(`Directory "${projectName}" already exists.`));
5812
+ console.error(error(`Directory "${projectName}" already exists.`));
5695
5813
  process.exitCode = 1;
5696
5814
  return;
5697
5815
  }
@@ -5699,7 +5817,7 @@ async function cmdNewProject(projectName, options) {
5699
5817
  try {
5700
5818
  initFlags = buildNewProjectInitArgs(options, inferredAdoption);
5701
5819
  } catch (err) {
5702
- console.error(error2(err.message));
5820
+ console.error(error(err.message));
5703
5821
  process.exitCode = 1;
5704
5822
  return;
5705
5823
  }
@@ -5882,11 +6000,11 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
5882
6000
  // src/commands/refresh.ts
5883
6001
  import { createHash } from "crypto";
5884
6002
  import { existsSync as existsSync23, readdirSync as readdirSync7, readFileSync as readFileSync17, statSync as statSync6 } from "fs";
5885
- import { join as join25 } from "path";
6003
+ import { isAbsolute as isAbsolute2, join as join25, relative as relative6 } from "path";
5886
6004
  import { collectMissingPackManifestFiles as collectMissingPackManifestFiles2 } from "@decantr/verifier";
5887
6005
  import { isV4 as isV46 } from "@decantr/essence-spec";
5888
6006
  var GREEN9 = "\x1B[32m";
5889
- var RED8 = "\x1B[31m";
6007
+ var RED7 = "\x1B[31m";
5890
6008
  var DIM9 = "\x1B[2m";
5891
6009
  var RESET9 = "\x1B[0m";
5892
6010
  function hashFile(path) {
@@ -5937,18 +6055,29 @@ function newestInputMtime(projectRoot) {
5937
6055
  fileMtimeMs(join25(projectRoot, ".decantr", "project.json"))
5938
6056
  );
5939
6057
  }
6058
+ function isContractOnlyProject2(projectRoot) {
6059
+ const projectJsonPath = join25(projectRoot, ".decantr", "project.json");
6060
+ if (!existsSync23(projectJsonPath)) return false;
6061
+ try {
6062
+ const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
6063
+ return projectJson.initialized?.adoptionMode === "contract-only";
6064
+ } catch {
6065
+ return false;
6066
+ }
6067
+ }
5940
6068
  function checkRefreshFreshness(projectRoot) {
5941
6069
  const contextDir = join25(projectRoot, ".decantr", "context");
5942
6070
  const generated = trackedGeneratedFiles(projectRoot);
5943
6071
  const reasons = [];
6072
+ const packHydrationOptional = isContractOnlyProject2(projectRoot);
5944
6073
  if (!existsSync23(join25(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
5945
6074
  if (!existsSync23(contextDir)) reasons.push(".decantr/context is missing.");
5946
6075
  if (!existsSync23(join25(contextDir, "scaffold.md"))) {
5947
6076
  reasons.push(".decantr/context/scaffold.md is missing.");
5948
6077
  }
5949
- if (!existsSync23(join25(contextDir, "pack-manifest.json"))) {
6078
+ if (!packHydrationOptional && !existsSync23(join25(contextDir, "pack-manifest.json"))) {
5950
6079
  reasons.push(".decantr/context/pack-manifest.json is missing.");
5951
- } else {
6080
+ } else if (existsSync23(join25(contextDir, "pack-manifest.json"))) {
5952
6081
  const missingPackFiles = collectMissingPackManifestFiles2(projectRoot);
5953
6082
  if (missingPackFiles.length > 0) {
5954
6083
  reasons.push(
@@ -5999,10 +6128,19 @@ function summarizeChanges(projectRoot, before, after) {
5999
6128
  unchanged: unchanged.sort()
6000
6129
  };
6001
6130
  }
6002
- function printRefreshSummary(summary) {
6131
+ function displayGeneratedPath(summary, file, displayRoot) {
6132
+ if (!displayRoot) return file;
6133
+ const absolutePath = join25(summary.projectRoot, file);
6134
+ const relativePath = relative6(displayRoot, absolutePath).replace(/\\/g, "/");
6135
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute2(relativePath)) {
6136
+ return relativePath;
6137
+ }
6138
+ return absolutePath;
6139
+ }
6140
+ function printRefreshSummary(summary, displayRoot) {
6003
6141
  if (summary.check) {
6004
6142
  if (summary.stale) {
6005
- console.log(`${RED8}Generated Decantr context is stale.${RESET9}`);
6143
+ console.log(`${RED7}Generated Decantr context is stale.${RESET9}`);
6006
6144
  for (const reason of summary.reasons) console.log(` ${reason}`);
6007
6145
  console.log(`${DIM9}Run \`decantr refresh\` to regenerate derived files.${RESET9}`);
6008
6146
  } else {
@@ -6018,7 +6156,9 @@ function printRefreshSummary(summary) {
6018
6156
  for (const [label, files] of groups) {
6019
6157
  if (files.length === 0) continue;
6020
6158
  console.log(`${GREEN9}${label}:${RESET9}`);
6021
- for (const file of files) console.log(` ${DIM9}${file}${RESET9}`);
6159
+ for (const file of files) {
6160
+ console.log(` ${DIM9}${displayGeneratedPath(summary, file, displayRoot)}${RESET9}`);
6161
+ }
6022
6162
  }
6023
6163
  if (groups.every(([, files]) => files.length === 0)) {
6024
6164
  console.log(`${GREEN9}Generated files were already current.${RESET9}`);
@@ -6027,7 +6167,7 @@ function printRefreshSummary(summary) {
6027
6167
  async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6028
6168
  const essencePath = join25(projectRoot, "decantr.essence.json");
6029
6169
  if (!existsSync23(essencePath)) {
6030
- console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6170
+ console.error(`${RED7}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6031
6171
  process.exitCode = 1;
6032
6172
  return;
6033
6173
  }
@@ -6037,14 +6177,14 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6037
6177
  const parsed = JSON.parse(raw);
6038
6178
  if (!isV46(parsed)) {
6039
6179
  console.error(
6040
- `${RED8}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6180
+ `${RED7}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6041
6181
  );
6042
6182
  process.exitCode = 1;
6043
6183
  return;
6044
6184
  }
6045
6185
  essence = parsed;
6046
6186
  } catch (e) {
6047
- console.error(`${RED8}Could not read essence: ${e.message}${RESET9}`);
6187
+ console.error(`${RED7}Could not read essence: ${e.message}${RESET9}`);
6048
6188
  process.exitCode = 1;
6049
6189
  return;
6050
6190
  }
@@ -6053,7 +6193,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6053
6193
  if (options.json) {
6054
6194
  console.log(JSON.stringify(summary2, null, 2));
6055
6195
  } else {
6056
- printRefreshSummary(summary2);
6196
+ printRefreshSummary(summary2, options.displayRoot);
6057
6197
  }
6058
6198
  if (summary2.stale) process.exitCode = 1;
6059
6199
  return;
@@ -6070,17 +6210,19 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6070
6210
  if (options.json) {
6071
6211
  console.log(JSON.stringify({ ...summary, result }, null, 2));
6072
6212
  } else if (options.listChanges) {
6073
- printRefreshSummary(summary);
6213
+ printRefreshSummary(summary, options.displayRoot);
6074
6214
  } else {
6075
6215
  console.log(`${GREEN9}Regenerated:${RESET9}`);
6076
- console.log(` ${DIM9}DECANTR.md${RESET9}`);
6216
+ console.log(
6217
+ ` ${DIM9}${displayGeneratedPath(summary, "DECANTR.md", options.displayRoot)}${RESET9}`
6218
+ );
6077
6219
  for (const css of result.cssFiles) {
6078
6220
  const rel2 = css.replace(projectRoot + "/", "");
6079
- console.log(` ${DIM9}${rel2}${RESET9}`);
6221
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6080
6222
  }
6081
6223
  for (const ctx of result.contextFiles) {
6082
6224
  const rel2 = ctx.replace(projectRoot + "/", "");
6083
- console.log(` ${DIM9}${rel2}${RESET9}`);
6225
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6084
6226
  }
6085
6227
  }
6086
6228
  console.log("");
@@ -6092,7 +6234,7 @@ import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync14 } from "fs";
6092
6234
  import { join as join26 } from "path";
6093
6235
  import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
6094
6236
  var GREEN10 = "\x1B[32m";
6095
- var RED9 = "\x1B[31m";
6237
+ var RED8 = "\x1B[31m";
6096
6238
  var DIM10 = "\x1B[2m";
6097
6239
  var CYAN5 = "\x1B[36m";
6098
6240
  var YELLOW6 = "\x1B[33m";
@@ -6106,13 +6248,13 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
6106
6248
  });
6107
6249
  const healthy = await apiClient.checkHealth();
6108
6250
  if (!healthy) {
6109
- console.error(`${RED9}Registry API is unavailable. Check your connection.${RESET10}`);
6251
+ console.error(`${RED8}Registry API is unavailable. Check your connection.${RESET10}`);
6110
6252
  process.exitCode = 1;
6111
6253
  return;
6112
6254
  }
6113
6255
  const types = options.type ? [options.type] : ALL_CONTENT_TYPES;
6114
6256
  if (options.type && !ALL_CONTENT_TYPES.includes(options.type)) {
6115
- console.error(`${RED9}Unknown content type: ${options.type}${RESET10}`);
6257
+ console.error(`${RED8}Unknown content type: ${options.type}${RESET10}`);
6116
6258
  console.error(`${DIM10}Valid types: ${ALL_CONTENT_TYPES.join(", ")}${RESET10}`);
6117
6259
  process.exitCode = 1;
6118
6260
  return;
@@ -6147,7 +6289,7 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6147
6289
  console.log(` ${GREEN10}\u2713${RESET10} ${type}: ${CYAN5}${itemCount}${RESET10} items`);
6148
6290
  } catch (e) {
6149
6291
  failed.push(type);
6150
- console.log(` ${RED9}\u2717${RESET10} ${type}: ${e.message}`);
6292
+ console.log(` ${RED8}\u2717${RESET10} ${type}: ${e.message}`);
6151
6293
  }
6152
6294
  }
6153
6295
  const manifest = {
@@ -6176,13 +6318,13 @@ import { existsSync as existsSync25, readFileSync as readFileSync18, rmSync as r
6176
6318
  import { join as join27 } from "path";
6177
6319
  import { isV4 as isV47 } from "@decantr/essence-spec";
6178
6320
  var GREEN11 = "\x1B[32m";
6179
- var RED10 = "\x1B[31m";
6321
+ var RED9 = "\x1B[31m";
6180
6322
  var DIM11 = "\x1B[2m";
6181
6323
  var RESET11 = "\x1B[0m";
6182
6324
  function readV4Essence2(projectRoot) {
6183
6325
  const essencePath = join27(projectRoot, "decantr.essence.json");
6184
6326
  if (!existsSync25(essencePath)) {
6185
- console.error(`${RED10}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6327
+ console.error(`${RED9}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6186
6328
  process.exitCode = 1;
6187
6329
  return null;
6188
6330
  }
@@ -6190,13 +6332,13 @@ function readV4Essence2(projectRoot) {
6190
6332
  try {
6191
6333
  parsed = JSON.parse(readFileSync18(essencePath, "utf-8"));
6192
6334
  } catch (e) {
6193
- console.error(`${RED10}Could not read essence: ${e.message}${RESET11}`);
6335
+ console.error(`${RED9}Could not read essence: ${e.message}${RESET11}`);
6194
6336
  process.exitCode = 1;
6195
6337
  return null;
6196
6338
  }
6197
6339
  if (!isV47(parsed)) {
6198
6340
  console.error(
6199
- `${RED10}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6341
+ `${RED9}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6200
6342
  );
6201
6343
  process.exitCode = 1;
6202
6344
  return null;
@@ -6206,6 +6348,15 @@ function readV4Essence2(projectRoot) {
6206
6348
  function writeEssence2(essencePath, essence) {
6207
6349
  writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n");
6208
6350
  }
6351
+ function readFlagValue2(args, name) {
6352
+ const prefix = `--${name}=`;
6353
+ for (let index = 0; index < args.length; index += 1) {
6354
+ const arg = args[index];
6355
+ if (arg === `--${name}` && args[index + 1]) return args[index + 1];
6356
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
6357
+ }
6358
+ return void 0;
6359
+ }
6209
6360
  function recomputeGlobalFeatures(essence) {
6210
6361
  const all = /* @__PURE__ */ new Set();
6211
6362
  for (const section of essence.blueprint.sections || []) {
@@ -6228,7 +6379,7 @@ function removeRoutes(essence, sectionId, pageId) {
6228
6379
  }
6229
6380
  async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6230
6381
  if (!sectionId) {
6231
- console.error(`${RED10}Usage: decantr remove section <sectionId>${RESET11}`);
6382
+ console.error(`${RED9}Usage: decantr remove section <sectionId>${RESET11}`);
6232
6383
  process.exitCode = 1;
6233
6384
  return;
6234
6385
  }
@@ -6238,7 +6389,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6238
6389
  const sections = essence.blueprint.sections;
6239
6390
  const idx = sections.findIndex((s) => s.id === sectionId);
6240
6391
  if (idx === -1) {
6241
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6392
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6242
6393
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6243
6394
  process.exitCode = 1;
6244
6395
  return;
@@ -6260,7 +6411,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6260
6411
  }
6261
6412
  async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6262
6413
  if (!path || !path.includes("/")) {
6263
- console.error(`${RED10}Usage: decantr remove page <section>/<page>${RESET11}`);
6414
+ console.error(`${RED9}Usage: decantr remove page <section>/<page>${RESET11}`);
6264
6415
  console.error(`${DIM11}Example: decantr remove page settings/notifications${RESET11}`);
6265
6416
  process.exitCode = 1;
6266
6417
  return;
@@ -6272,14 +6423,14 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6272
6423
  const sections = essence.blueprint.sections;
6273
6424
  const section = sections.find((s) => s.id === sectionId);
6274
6425
  if (!section) {
6275
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6426
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6276
6427
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6277
6428
  process.exitCode = 1;
6278
6429
  return;
6279
6430
  }
6280
6431
  const pageIdx = section.pages.findIndex((p) => p.id === pageId);
6281
6432
  if (pageIdx === -1) {
6282
- console.error(`${RED10}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6433
+ console.error(`${RED9}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6283
6434
  console.error(`${DIM11}Available pages: ${section.pages.map((p) => p.id).join(", ")}${RESET11}`);
6284
6435
  process.exitCode = 1;
6285
6436
  return;
@@ -6296,7 +6447,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6296
6447
  }
6297
6448
  async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6298
6449
  if (!feature) {
6299
- console.error(`${RED10}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6450
+ console.error(`${RED9}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6300
6451
  process.exitCode = 1;
6301
6452
  return;
6302
6453
  }
@@ -6304,15 +6455,12 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6304
6455
  if (!loaded) return;
6305
6456
  const { essence, essencePath } = loaded;
6306
6457
  let sectionId;
6307
- const sectionIdx = args.indexOf("--section");
6308
- if (sectionIdx !== -1 && args[sectionIdx + 1]) {
6309
- sectionId = args[sectionIdx + 1];
6310
- }
6458
+ sectionId = readFlagValue2(args, "section");
6311
6459
  if (sectionId) {
6312
6460
  const sections = essence.blueprint.sections;
6313
6461
  const section = sections.find((s) => s.id === sectionId);
6314
6462
  if (!section) {
6315
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6463
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6316
6464
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6317
6465
  process.exitCode = 1;
6318
6466
  return;
@@ -6340,7 +6488,7 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6340
6488
  import { existsSync as existsSync26, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
6341
6489
  import { join as join28 } from "path";
6342
6490
  var GREEN12 = "\x1B[32m";
6343
- var RED11 = "\x1B[31m";
6491
+ var RED10 = "\x1B[31m";
6344
6492
  var YELLOW7 = "\x1B[33m";
6345
6493
  var RESET12 = "\x1B[0m";
6346
6494
  var DIM12 = "\x1B[2m";
@@ -6359,12 +6507,12 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
6359
6507
  try {
6360
6508
  entries = JSON.parse(readFileSync19(driftLogPath, "utf-8"));
6361
6509
  } catch {
6362
- console.error(`${RED11}Could not parse drift-log.json${RESET12}`);
6510
+ console.error(`${RED10}Could not parse drift-log.json${RESET12}`);
6363
6511
  process.exitCode = 1;
6364
6512
  return;
6365
6513
  }
6366
6514
  if (!Array.isArray(entries)) {
6367
- console.error(`${RED11}drift-log.json is not an array${RESET12}`);
6515
+ console.error(`${RED10}drift-log.json is not an array${RESET12}`);
6368
6516
  process.exitCode = 1;
6369
6517
  return;
6370
6518
  }
@@ -6382,7 +6530,7 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6382
6530
  `);
6383
6531
  for (let i = 0; i < unresolved.length; i++) {
6384
6532
  const entry = unresolved[i];
6385
- const severityColor = entry.severity === "error" ? RED11 : YELLOW7;
6533
+ const severityColor = entry.severity === "error" ? RED10 : YELLOW7;
6386
6534
  const icon = entry.severity === "error" ? "x" : "!";
6387
6535
  console.log(
6388
6536
  ` ${severityColor}${icon}${RESET12} ${BOLD6}#${i + 1}${RESET12} [${entry.rule}] ${entry.message}`
@@ -6665,7 +6813,7 @@ import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSy
6665
6813
  import { join as join29 } from "path";
6666
6814
  import { isV4 as isV48 } from "@decantr/essence-spec";
6667
6815
  var GREEN14 = "\x1B[32m";
6668
- var RED12 = "\x1B[31m";
6816
+ var RED11 = "\x1B[31m";
6669
6817
  var YELLOW8 = "\x1B[33m";
6670
6818
  var DIM14 = "\x1B[2m";
6671
6819
  var RESET14 = "\x1B[0m";
@@ -6674,14 +6822,14 @@ var VALID_THEME_MODES = ["light", "dark", "auto"];
6674
6822
  async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6675
6823
  if (!themeName) {
6676
6824
  console.error(
6677
- `${RED12}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6825
+ `${RED11}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6678
6826
  );
6679
6827
  process.exitCode = 1;
6680
6828
  return;
6681
6829
  }
6682
6830
  const essencePath = join29(projectRoot, "decantr.essence.json");
6683
6831
  if (!existsSync27(essencePath)) {
6684
- console.error(`${RED12}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6832
+ console.error(`${RED11}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6685
6833
  process.exitCode = 1;
6686
6834
  return;
6687
6835
  }
@@ -6689,13 +6837,13 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6689
6837
  try {
6690
6838
  parsed = JSON.parse(readFileSync20(essencePath, "utf-8"));
6691
6839
  } catch (e) {
6692
- console.error(`${RED12}Could not read essence: ${e.message}${RESET14}`);
6840
+ console.error(`${RED11}Could not read essence: ${e.message}${RESET14}`);
6693
6841
  process.exitCode = 1;
6694
6842
  return;
6695
6843
  }
6696
6844
  if (!isV48(parsed)) {
6697
6845
  console.error(
6698
- `${RED12}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6846
+ `${RED11}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6699
6847
  );
6700
6848
  process.exitCode = 1;
6701
6849
  return;
@@ -6717,14 +6865,14 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6717
6865
  }
6718
6866
  if (shape && !VALID_THEME_SHAPES.includes(shape)) {
6719
6867
  console.error(
6720
- `${RED12}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6868
+ `${RED11}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6721
6869
  );
6722
6870
  process.exitCode = 1;
6723
6871
  return;
6724
6872
  }
6725
6873
  if (mode && !VALID_THEME_MODES.includes(mode)) {
6726
6874
  console.error(
6727
- `${RED12}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6875
+ `${RED11}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6728
6876
  );
6729
6877
  process.exitCode = 1;
6730
6878
  return;
@@ -7228,7 +7376,7 @@ function importTheme(projectRoot, sourcePath) {
7228
7376
  var BOLD9 = "\x1B[1m";
7229
7377
  var DIM16 = "\x1B[2m";
7230
7378
  var RESET16 = "\x1B[0m";
7231
- var RED13 = "\x1B[31m";
7379
+ var RED12 = "\x1B[31m";
7232
7380
  var GREEN16 = "\x1B[32m";
7233
7381
  var CYAN9 = "\x1B[36m";
7234
7382
  var YELLOW10 = "\x1B[33m";
@@ -7240,8 +7388,8 @@ ${BOLD9}${text}${RESET16}
7240
7388
  function success3(text) {
7241
7389
  return `${GREEN16}${text}${RESET16}`;
7242
7390
  }
7243
- function error3(text) {
7244
- return `${RED13}${text}${RESET16}`;
7391
+ function error2(text) {
7392
+ return `${RED12}${text}${RESET16}`;
7245
7393
  }
7246
7394
  function dim3(text) {
7247
7395
  return `${DIM16}${text}${RESET16}`;
@@ -7751,7 +7899,7 @@ function getPublicAPIClient() {
7751
7899
  });
7752
7900
  }
7753
7901
  function resolveUserPath(inputPath, cwd = process.cwd()) {
7754
- return isAbsolute(inputPath) ? inputPath : resolve4(cwd, inputPath);
7902
+ return isAbsolute3(inputPath) ? inputPath : resolve4(cwd, inputPath);
7755
7903
  }
7756
7904
  function extractHostedAssetPaths(indexHtml) {
7757
7905
  const assetPaths = /* @__PURE__ */ new Set();
@@ -8345,22 +8493,22 @@ function patternCandidateFromRegistryItem(item, source) {
8345
8493
  { source, slug }
8346
8494
  );
8347
8495
  }
8348
- function readSuggestCodeContext(route, file) {
8496
+ function readSuggestCodeContext(projectRoot, route, file) {
8349
8497
  const pieces = [];
8350
8498
  if (file) {
8351
- const resolved = isAbsolute(file) ? file : join31(process.cwd(), file);
8499
+ const resolved = isAbsolute3(file) ? file : join31(projectRoot, file);
8352
8500
  if (existsSync29(resolved)) {
8353
8501
  pieces.push(readFileSync22(resolved, "utf-8"));
8354
8502
  }
8355
8503
  }
8356
8504
  if (route) {
8357
- const analysisPath = join31(process.cwd(), ".decantr", "analysis.json");
8505
+ const analysisPath = join31(projectRoot, ".decantr", "analysis.json");
8358
8506
  if (existsSync29(analysisPath)) {
8359
8507
  try {
8360
8508
  const analysis = JSON.parse(readFileSync22(analysisPath, "utf-8"));
8361
8509
  const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
8362
8510
  if (routeEntry?.file) {
8363
- const resolved = join31(process.cwd(), routeEntry.file);
8511
+ const resolved = join31(projectRoot, routeEntry.file);
8364
8512
  if (existsSync29(resolved)) {
8365
8513
  pieces.push(readFileSync22(resolved, "utf-8"));
8366
8514
  }
@@ -8371,6 +8519,28 @@ function readSuggestCodeContext(route, file) {
8371
8519
  }
8372
8520
  return pieces.join("\n\n").slice(0, 2e4);
8373
8521
  }
8522
+ function localPatternMatches(projectRoot, query) {
8523
+ if (!projectRoot) return [];
8524
+ const pack = readLocalPatternPack(projectRoot);
8525
+ const patterns = Array.isArray(pack?.patterns) ? pack.patterns : [];
8526
+ const queryTerms = query.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1);
8527
+ if (queryTerms.length === 0) return [];
8528
+ return patterns.map((pattern) => {
8529
+ const id = typeof pattern.id === "string" ? pattern.id : "local-pattern";
8530
+ const label = typeof pattern.label === "string" ? pattern.label : null;
8531
+ const role = typeof pattern.role === "string" ? pattern.role : null;
8532
+ const haystack = [
8533
+ id,
8534
+ label,
8535
+ role,
8536
+ typeof pattern.decide === "string" ? pattern.decide : null,
8537
+ ...Array.isArray(pattern.appliesTo) ? pattern.appliesTo : [],
8538
+ ...Array.isArray(pattern.componentPaths) ? pattern.componentPaths : []
8539
+ ].filter((entry) => typeof entry === "string").join(" ").toLowerCase();
8540
+ const score = queryTerms.reduce((sum, term) => sum + (haystack.includes(term) ? 1 : 0), 0);
8541
+ return { id, label, role, score };
8542
+ }).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, 5);
8543
+ }
8374
8544
  async function loadPatternDiscoveryCandidates(registryClient) {
8375
8545
  const candidates = [];
8376
8546
  const seen = /* @__PURE__ */ new Set();
@@ -8419,9 +8589,9 @@ async function cmdSuggest(query, options = {}) {
8419
8589
  }
8420
8590
  }
8421
8591
  const registryClient = new RegistryClient({
8422
- cacheDir: join31(process.cwd(), ".decantr", "cache")
8592
+ cacheDir: join31(options.projectRoot ?? process.cwd(), ".decantr", "cache")
8423
8593
  });
8424
- const code = options.fromCode || options.file ? readSuggestCodeContext(options.route, options.file) : "";
8594
+ const code = options.fromCode || options.file ? readSuggestCodeContext(options.projectRoot ?? process.cwd(), options.route, options.file) : "";
8425
8595
  const candidates = await loadPatternDiscoveryCandidates(registryClient);
8426
8596
  const matches = rankPatternCandidates(
8427
8597
  {
@@ -8452,6 +8622,16 @@ async function cmdSuggest(query, options = {}) {
8452
8622
  `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
8453
8623
  )
8454
8624
  );
8625
+ const localMatches = localPatternMatches(options.projectRoot, query);
8626
+ if (localMatches.length > 0) {
8627
+ console.log(`${BOLD9}Project-owned local law:${RESET16}`);
8628
+ for (const match of localMatches) {
8629
+ const details = [match.label, match.role].filter(Boolean).join(" | ");
8630
+ console.log(` ${cyan3(match.id)}${details ? ` ${dim3(details)}` : ""}`);
8631
+ }
8632
+ console.log("");
8633
+ console.log(`${BOLD9}Registry patterns:${RESET16}`);
8634
+ }
8455
8635
  for (const match of matches.slice(0, 8)) {
8456
8636
  const candidate = match.candidate;
8457
8637
  const slug = candidate.slug || candidate.id;
@@ -8475,7 +8655,7 @@ async function cmdSuggest(query, options = {}) {
8475
8655
  }
8476
8656
  async function cmdGet(type, id) {
8477
8657
  if (!isGetContentType(type)) {
8478
- console.error(error3(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8658
+ console.error(error2(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8479
8659
  process.exitCode = 1;
8480
8660
  return;
8481
8661
  }
@@ -8493,7 +8673,7 @@ async function cmdGet(type, id) {
8493
8673
  console.log(JSON.stringify(bundled.data, null, 2));
8494
8674
  return;
8495
8675
  }
8496
- console.error(error3(`${type} "${id}" not found.`));
8676
+ console.error(error2(`${type} "${id}" not found.`));
8497
8677
  process.exitCode = 1;
8498
8678
  return;
8499
8679
  }
@@ -8503,7 +8683,7 @@ async function cmdValidate(path) {
8503
8683
  try {
8504
8684
  raw = readFileSync22(essencePath, "utf-8");
8505
8685
  } catch {
8506
- console.error(error3(`Could not read ${essencePath}`));
8686
+ console.error(error2(`Could not read ${essencePath}`));
8507
8687
  process.exitCode = 1;
8508
8688
  return;
8509
8689
  }
@@ -8511,7 +8691,7 @@ async function cmdValidate(path) {
8511
8691
  try {
8512
8692
  essence = JSON.parse(raw);
8513
8693
  } catch (e) {
8514
- console.error(error3(`Invalid JSON: ${e.message}`));
8694
+ console.error(error2(`Invalid JSON: ${e.message}`));
8515
8695
  process.exitCode = 1;
8516
8696
  return;
8517
8697
  }
@@ -8521,9 +8701,9 @@ async function cmdValidate(path) {
8521
8701
  if (result.valid) {
8522
8702
  console.log(success3(`Essence is valid (${detectedVersion}).`));
8523
8703
  } else {
8524
- console.error(error3("Validation failed:"));
8704
+ console.error(error2("Validation failed:"));
8525
8705
  for (const err of result.errors) {
8526
- console.error(` ${RED13}${err}${RESET16}`);
8706
+ console.error(` ${RED12}${err}${RESET16}`);
8527
8707
  }
8528
8708
  process.exitCode = 1;
8529
8709
  return;
@@ -8562,7 +8742,7 @@ async function cmdValidate(path) {
8562
8742
  async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet) {
8563
8743
  if (!isApiContentType(type)) {
8564
8744
  console.error(
8565
- error3(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8745
+ error2(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8566
8746
  );
8567
8747
  process.exitCode = 1;
8568
8748
  return;
@@ -8724,7 +8904,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8724
8904
  const proposal = readBrownfieldProposal(input.projectRoot);
8725
8905
  if (!proposal) {
8726
8906
  console.log(
8727
- error3(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8907
+ error2(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8728
8908
  );
8729
8909
  console.log(
8730
8910
  dim3(
@@ -8739,7 +8919,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8739
8919
  let essence;
8740
8920
  let backupPath = null;
8741
8921
  if (input.mode === "accept" && hasEssence) {
8742
- console.log(error3("Refusing to accept proposal over an existing decantr.essence.json."));
8922
+ console.log(error2("Refusing to accept proposal over an existing decantr.essence.json."));
8743
8923
  console.log(
8744
8924
  dim3(
8745
8925
  "Use `--merge-proposal` to preserve the existing contract or `--replace-essence` for an explicit destructive replacement."
@@ -8752,7 +8932,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8752
8932
  const existing = JSON.parse(readFileSync22(essencePath, "utf-8"));
8753
8933
  if (!isV49(existing)) {
8754
8934
  console.log(
8755
- error3(
8935
+ error2(
8756
8936
  "Existing essence is not v4. Run `decantr migrate --to v4` before merging a brownfield proposal."
8757
8937
  )
8758
8938
  );
@@ -8766,10 +8946,10 @@ async function applyAcceptedBrownfieldProposal(input) {
8766
8946
  const validation = validateEssence2(essence);
8767
8947
  if (!validation.valid) {
8768
8948
  console.log(
8769
- error3("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8949
+ error2("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8770
8950
  );
8771
8951
  for (const validationError of validation.errors) {
8772
- console.log(` ${RED13}${validationError}${RESET16}`);
8952
+ console.log(` ${RED12}${validationError}${RESET16}`);
8773
8953
  }
8774
8954
  process.exitCode = 1;
8775
8955
  return;
@@ -8815,13 +8995,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8815
8995
  }
8816
8996
  const appliedRuleFiles = input.assistantBridge === "apply" ? applyAssistantBridge(input.projectRoot, input.detected) : [];
8817
8997
  console.log(success3("\nBrownfield proposal accepted.\n"));
8998
+ const projectLabel = input.workspaceInfo.appRoot !== input.workspaceInfo.workspaceRoot ? relative7(input.workspaceInfo.workspaceRoot, input.workspaceInfo.appRoot).replace(/\\/g, "/") : void 0;
8818
8999
  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`);
9000
+ console.log(
9001
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "decantr.essence.json"))} Observed brownfield contract`
9002
+ );
9003
+ console.log(
9004
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "DECANTR.md"))} Reconciled assistant guidance`
9005
+ );
9006
+ console.log(
9007
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/project.json"))} Brownfield attach metadata`
9008
+ );
9009
+ console.log(
9010
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/"))} Generated contract context`
9011
+ );
8823
9012
  if (assistantBridgePath) {
8824
- console.log(` ${cyan3(".decantr/context/assistant-bridge.md")} Assistant bridge preview`);
9013
+ console.log(
9014
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/assistant-bridge.md"))} Assistant bridge preview`
9015
+ );
8825
9016
  }
8826
9017
  if (appliedRuleFiles.length > 0) {
8827
9018
  console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
@@ -8832,16 +9023,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8832
9023
  console.log("");
8833
9024
  console.log(" Generated context:");
8834
9025
  for (const contextFile of refreshResult.contextFiles.slice(0, 8)) {
8835
- console.log(` ${dim3(contextFile.replace(`${input.projectRoot}/`, ""))}`);
9026
+ console.log(
9027
+ ` ${dim3(displayProjectPath(input.workspaceInfo, contextFile.replace(`${input.projectRoot}/`, "")))}`
9028
+ );
8836
9029
  }
8837
9030
  if (refreshResult.contextFiles.length > 8) {
8838
9031
  console.log(` ${dim3(`(+${refreshResult.contextFiles.length - 8} more)`)}`);
8839
9032
  }
8840
9033
  console.log("");
8841
9034
  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`);
9035
+ console.log(
9036
+ ` 1. Run ${cyan3(withProject("decantr check --brownfield", projectLabel))} to verify contract coverage`
9037
+ );
9038
+ console.log(
9039
+ ` 2. Read ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/brownfield-report.md"))} for unresolved doctrine risks`
9040
+ );
9041
+ console.log(
9042
+ ` 3. Use ${cyan3(withProject("decantr rules preview", projectLabel))} before mutating assistant rule files`
9043
+ );
8845
9044
  console.log("");
8846
9045
  }
8847
9046
  async function cmdInit(args) {
@@ -8898,7 +9097,7 @@ async function cmdInit(args) {
8898
9097
  }
8899
9098
  if (policy.workflowMode === "brownfield-attach" && detected.existingEssence) {
8900
9099
  console.log(
8901
- error3("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
9100
+ error2("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
8902
9101
  );
8903
9102
  console.log(
8904
9103
  dim3(
@@ -8909,7 +9108,7 @@ async function cmdInit(args) {
8909
9108
  return;
8910
9109
  }
8911
9110
  if (policy.workflowMode === "brownfield-attach" && readBrownfieldProposal(projectRoot)) {
8912
- console.log(error3("Observed brownfield proposal found, but it was not accepted."));
9111
+ console.log(error2("Observed brownfield proposal found, but it was not accepted."));
8913
9112
  console.log(
8914
9113
  dim3(
8915
9114
  "Review `.decantr/brownfield-report.md`, then run `decantr init --existing --accept-proposal`."
@@ -8930,7 +9129,7 @@ async function cmdInit(args) {
8930
9129
  console.log(dim3(` Seeded offline registry content from ${offlineSeed.strategy}.`));
8931
9130
  } else if (requestedBlueprint || requestedArchetype) {
8932
9131
  console.log(
8933
- error3("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
9132
+ error2("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
8934
9133
  );
8935
9134
  console.log(
8936
9135
  dim3(
@@ -8998,7 +9197,7 @@ ${YELLOW10}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
8998
9197
  }
8999
9198
  if (requestedBlueprint || requestedArchetype) {
9000
9199
  console.log(
9001
- error3(
9200
+ error2(
9002
9201
  "\nThe requested blueprint/archetype could not be resolved from the hosted registry or local cache."
9003
9202
  )
9004
9203
  );
@@ -9187,7 +9386,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9187
9386
  }
9188
9387
  } else {
9189
9388
  if (requestedBlueprint) {
9190
- console.log(error3(` Error: Could not fetch blueprint "${options.blueprint}".`));
9389
+ console.log(error2(` Error: Could not fetch blueprint "${options.blueprint}".`));
9191
9390
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9192
9391
  process.exitCode = 1;
9193
9392
  return;
@@ -9202,7 +9401,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9202
9401
  archetypeData = mapRegistryArchetypeToArchetypeData(archetypeResult.data);
9203
9402
  } else {
9204
9403
  if (requestedArchetype) {
9205
- console.log(error3(` Error: Could not fetch archetype "${options.archetype}".`));
9404
+ console.log(error2(` Error: Could not fetch archetype "${options.archetype}".`));
9206
9405
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9207
9406
  process.exitCode = 1;
9208
9407
  return;
@@ -9219,7 +9418,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9219
9418
  themeData = mapRegistryThemeToThemeData(themeResult.data);
9220
9419
  } else {
9221
9420
  if (requestedTheme) {
9222
- console.log(error3(` Error: Could not fetch theme "${options.theme}".`));
9421
+ console.log(error2(` Error: Could not fetch theme "${options.theme}".`));
9223
9422
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9224
9423
  process.exitCode = 1;
9225
9424
  return;
@@ -9329,7 +9528,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9329
9528
  const essence = JSON.parse(essenceContent);
9330
9529
  const validation = validateEssence2(essence);
9331
9530
  if (!validation.valid) {
9332
- console.log(error3(`
9531
+ console.log(error2(`
9333
9532
  Validation warnings: ${validation.errors.join(", ")}`));
9334
9533
  }
9335
9534
  console.log("");
@@ -9379,13 +9578,12 @@ Validation warnings: ${validation.errors.join(", ")}`));
9379
9578
  console.log(dim3('Run "decantr sync" when online to get the latest registry content.'));
9380
9579
  }
9381
9580
  }
9382
- async function cmdStatus() {
9383
- const projectRoot = process.cwd();
9581
+ async function cmdStatus(projectRoot = process.cwd()) {
9384
9582
  const essencePath = join31(projectRoot, "decantr.essence.json");
9385
9583
  const projectJsonPath = join31(projectRoot, ".decantr", "project.json");
9386
9584
  console.log(heading2("Decantr Project Status"));
9387
9585
  if (!existsSync29(essencePath)) {
9388
- console.log(`${RED13}No decantr.essence.json found.${RESET16}`);
9586
+ console.log(`${RED12}No decantr.essence.json found.${RESET16}`);
9389
9587
  console.log(dim3('Run "decantr init" to create one.'));
9390
9588
  return;
9391
9589
  }
@@ -9397,7 +9595,7 @@ async function cmdStatus() {
9397
9595
  if (validation.valid) {
9398
9596
  console.log(` ${GREEN16}Valid${RESET16} (${essenceVersion})`);
9399
9597
  } else {
9400
- console.log(` ${RED13}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9598
+ console.log(` ${RED12}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9401
9599
  }
9402
9600
  if (isV49(essence)) {
9403
9601
  const v4 = essence;
@@ -9434,7 +9632,7 @@ async function cmdStatus() {
9434
9632
  console.log(` ${YELLOW10}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9435
9633
  }
9436
9634
  } catch (e) {
9437
- console.log(` ${RED13}Error reading essence: ${e.message}${RESET16}`);
9635
+ console.log(` ${RED12}Error reading essence: ${e.message}${RESET16}`);
9438
9636
  }
9439
9637
  console.log("");
9440
9638
  console.log(`${BOLD9}Sync Status:${RESET16}`);
@@ -9480,7 +9678,7 @@ function printVerificationFindings(findings) {
9480
9678
  return;
9481
9679
  }
9482
9680
  for (const finding of findings) {
9483
- const color = finding.severity === "error" ? RED13 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9681
+ const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9484
9682
  console.log(
9485
9683
  ` ${color}[${finding.severity.toUpperCase()}]${RESET16} ${finding.category}: ${finding.message}`
9486
9684
  );
@@ -9496,7 +9694,7 @@ function printProjectAuditReport(report) {
9496
9694
  if (report.valid) {
9497
9695
  console.log(success3("Project contract is valid."));
9498
9696
  } else {
9499
- console.log(`${RED13}Project audit found blocking issues.${RESET16}`);
9697
+ console.log(`${RED12}Project audit found blocking issues.${RESET16}`);
9500
9698
  }
9501
9699
  console.log("");
9502
9700
  console.log(`${BOLD9}Summary:${RESET16}`);
@@ -9585,13 +9783,12 @@ async function cmdAudit(filePath) {
9585
9783
  console.log(dim3("Project audit completed with advisory findings."));
9586
9784
  }
9587
9785
  } catch (e) {
9588
- console.log(`${RED13}Error: ${e.message}${RESET16}`);
9786
+ console.log(`${RED12}Error: ${e.message}${RESET16}`);
9589
9787
  process.exitCode = 1;
9590
9788
  }
9591
9789
  }
9592
- async function cmdTheme(args) {
9790
+ async function cmdTheme(args, projectRoot = process.cwd()) {
9593
9791
  const subcommand = args[0];
9594
- const projectRoot = process.cwd();
9595
9792
  if (!subcommand || subcommand === "help") {
9596
9793
  console.log(`
9597
9794
  ${BOLD9}decantr theme${RESET16} \u2014 Manage custom themes
@@ -9616,7 +9813,7 @@ ${BOLD9}Examples:${RESET16}
9616
9813
  case "create": {
9617
9814
  const name = args[1];
9618
9815
  if (!name) {
9619
- console.error(error3("Usage: decantr theme create <name>"));
9816
+ console.error(error2("Usage: decantr theme create <name>"));
9620
9817
  process.exitCode = 1;
9621
9818
  return;
9622
9819
  }
@@ -9628,7 +9825,7 @@ ${BOLD9}Examples:${RESET16}
9628
9825
  console.log("");
9629
9826
  console.log(`Use in essence: ${cyan3(`"id": "custom:${name}"`)}`);
9630
9827
  } else {
9631
- console.error(error3(result.error || "Failed to create theme"));
9828
+ console.error(error2(result.error || "Failed to create theme"));
9632
9829
  process.exitCode = 1;
9633
9830
  }
9634
9831
  break;
@@ -9649,13 +9846,13 @@ ${BOLD9}Examples:${RESET16}
9649
9846
  case "validate": {
9650
9847
  const name = args[1];
9651
9848
  if (!name) {
9652
- console.error(error3("Usage: decantr theme validate <name>"));
9849
+ console.error(error2("Usage: decantr theme validate <name>"));
9653
9850
  process.exitCode = 1;
9654
9851
  return;
9655
9852
  }
9656
9853
  const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
9657
9854
  if (!existsSync29(themePath)) {
9658
- console.error(error3(`Theme "${name}" not found at ${themePath}`));
9855
+ console.error(error2(`Theme "${name}" not found at ${themePath}`));
9659
9856
  process.exitCode = 1;
9660
9857
  return;
9661
9858
  }
@@ -9665,14 +9862,14 @@ ${BOLD9}Examples:${RESET16}
9665
9862
  if (result.valid) {
9666
9863
  console.log(success3(`Custom theme "${name}" is valid`));
9667
9864
  } else {
9668
- console.error(error3("Validation failed:"));
9865
+ console.error(error2("Validation failed:"));
9669
9866
  for (const err of result.errors) {
9670
- console.error(` ${RED13}${err}${RESET16}`);
9867
+ console.error(` ${RED12}${err}${RESET16}`);
9671
9868
  }
9672
9869
  process.exitCode = 1;
9673
9870
  }
9674
9871
  } catch (e) {
9675
- console.error(error3(`Invalid JSON: ${e.message}`));
9872
+ console.error(error2(`Invalid JSON: ${e.message}`));
9676
9873
  process.exitCode = 1;
9677
9874
  }
9678
9875
  break;
@@ -9680,7 +9877,7 @@ ${BOLD9}Examples:${RESET16}
9680
9877
  case "delete": {
9681
9878
  const name = args[1];
9682
9879
  if (!name) {
9683
- console.error(error3("Usage: decantr theme delete <name>"));
9880
+ console.error(error2("Usage: decantr theme delete <name>"));
9684
9881
  process.exitCode = 1;
9685
9882
  return;
9686
9883
  }
@@ -9688,7 +9885,7 @@ ${BOLD9}Examples:${RESET16}
9688
9885
  if (result.success) {
9689
9886
  console.log(success3(`Deleted custom theme "${name}"`));
9690
9887
  } else {
9691
- console.error(error3(result.error || "Failed to delete theme"));
9888
+ console.error(error2(result.error || "Failed to delete theme"));
9692
9889
  process.exitCode = 1;
9693
9890
  }
9694
9891
  break;
@@ -9696,7 +9893,7 @@ ${BOLD9}Examples:${RESET16}
9696
9893
  case "import": {
9697
9894
  const sourcePath = args[1];
9698
9895
  if (!sourcePath) {
9699
- console.error(error3("Usage: decantr theme import <path>"));
9896
+ console.error(error2("Usage: decantr theme import <path>"));
9700
9897
  process.exitCode = 1;
9701
9898
  return;
9702
9899
  }
@@ -9705,9 +9902,9 @@ ${BOLD9}Examples:${RESET16}
9705
9902
  console.log(success3("Theme imported successfully"));
9706
9903
  console.log(dim3(` Path: ${result.path}`));
9707
9904
  } else {
9708
- console.error(error3("Import failed:"));
9905
+ console.error(error2("Import failed:"));
9709
9906
  for (const err of result.errors || []) {
9710
- console.error(` ${RED13}${err}${RESET16}`);
9907
+ console.error(` ${RED12}${err}${RESET16}`);
9711
9908
  }
9712
9909
  process.exitCode = 1;
9713
9910
  }
@@ -9716,7 +9913,7 @@ ${BOLD9}Examples:${RESET16}
9716
9913
  case "switch": {
9717
9914
  const name = args[1];
9718
9915
  if (!name) {
9719
- console.error(error3("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9916
+ console.error(error2("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9720
9917
  process.exitCode = 1;
9721
9918
  return;
9722
9919
  }
@@ -9724,7 +9921,7 @@ ${BOLD9}Examples:${RESET16}
9724
9921
  break;
9725
9922
  }
9726
9923
  default:
9727
- console.error(error3(`Unknown theme command: ${subcommand}`));
9924
+ console.error(error2(`Unknown theme command: ${subcommand}`));
9728
9925
  process.exitCode = 1;
9729
9926
  }
9730
9927
  }
@@ -9791,6 +9988,44 @@ function withoutWorkflowOnlyFlags(args) {
9791
9988
  function withProject(command, projectArg) {
9792
9989
  return projectArg ? `${command} --project ${projectArg}` : command;
9793
9990
  }
9991
+ function displayProjectPath(workspaceInfo, projectPath) {
9992
+ const absolutePath = join31(workspaceInfo.appRoot, projectPath);
9993
+ const relativePath = relative7(workspaceInfo.cwd, absolutePath).replace(/\\/g, "/");
9994
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute3(relativePath)) {
9995
+ return relativePath;
9996
+ }
9997
+ return absolutePath;
9998
+ }
9999
+ function stripProjectArgs(args, startIndex = 1) {
10000
+ const stripped = [args[0]];
10001
+ for (let index = startIndex; index < args.length; index += 1) {
10002
+ const arg = args[index];
10003
+ if (arg === "--project" && args[index + 1]) {
10004
+ index += 1;
10005
+ continue;
10006
+ }
10007
+ if (arg.startsWith("--project=")) continue;
10008
+ stripped.push(arg);
10009
+ }
10010
+ return stripped;
10011
+ }
10012
+ function normalizedProjectPath(value) {
10013
+ if (!value) return null;
10014
+ return value.replace(/\\/g, "/").replace(/\/+$/g, "");
10015
+ }
10016
+ function printProjectNotFound(projectArg, commandName) {
10017
+ console.error(error2(`decantr ${commandName} could not find project path: ${projectArg}`));
10018
+ console.error(dim3("Pass an existing app path, for example `--project apps/web`."));
10019
+ }
10020
+ function ensureAllowedFlags(flags, allowed, commandName) {
10021
+ const allowedSet = new Set(allowed);
10022
+ const unknown = Object.keys(flags).filter((flag) => !allowedSet.has(flag));
10023
+ if (unknown.length === 0) return true;
10024
+ console.error(error2(`Unsupported option for decantr ${commandName}: --${unknown[0]}`));
10025
+ console.error(dim3("Run `decantr help` or the command-specific help to see supported options."));
10026
+ process.exitCode = 1;
10027
+ return false;
10028
+ }
9794
10029
  function compilePacksCommandForProject(projectArg) {
9795
10030
  const essencePath = projectArg ? `${projectArg}/decantr.essence.json` : "decantr.essence.json";
9796
10031
  return `decantr registry compile-packs ${essencePath} --write-context`;
@@ -9801,7 +10036,7 @@ function firstWorkspaceCandidate(workspaceInfo) {
9801
10036
  function printWorkspaceProjectSelection(workspaceInfo, commandName = "command") {
9802
10037
  const candidate = firstWorkspaceCandidate(workspaceInfo);
9803
10038
  const noun = commandName === "adopt" ? "Brownfield adoption" : `decantr ${commandName}`;
9804
- console.log(error3(`${noun} needs an app path.`));
10039
+ console.log(error2(`${noun} needs an app path.`));
9805
10040
  console.log("");
9806
10041
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9807
10042
  console.log("Install Decantr at the workspace root, then attach it to one app with --project.");
@@ -9821,10 +10056,47 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
9821
10056
  }
9822
10057
  function printMonorepoSetupGuidance(workspaceInfo) {
9823
10058
  const candidate = firstWorkspaceCandidate(workspaceInfo);
10059
+ const attachedProjects = workspaceInfo.appCandidates.filter(
10060
+ (appCandidate) => existsSync29(join31(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
10061
+ );
10062
+ const firstAttached = attachedProjects[0];
9824
10063
  console.log(heading2("Decantr Setup"));
9825
10064
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9826
10065
  console.log(` Workspace root: ${workspaceInfo.workspaceRoot}`);
9827
10066
  console.log("");
10067
+ if (firstAttached) {
10068
+ console.log("Decantr is already attached to at least one app.");
10069
+ console.log("");
10070
+ console.log("Attached projects:");
10071
+ for (const project of attachedProjects) {
10072
+ console.log(` ${project}`);
10073
+ }
10074
+ console.log("");
10075
+ console.log(`${BOLD9}Next:${RESET16}`);
10076
+ console.log(
10077
+ ` ${cyan3(`decantr doctor --project ${firstAttached}`)} Explain current state and next command`
10078
+ );
10079
+ console.log(
10080
+ ` ${cyan3(`decantr task <route> "<change>" --project ${firstAttached}`)} Prepare LLM context before edits`
10081
+ );
10082
+ console.log(
10083
+ ` ${cyan3(`decantr verify --brownfield --local-patterns --project ${firstAttached}`)} Check after edits`
10084
+ );
10085
+ console.log(
10086
+ ` ${cyan3(`decantr ci init --project ${firstAttached}`)} Wire the app into CI`
10087
+ );
10088
+ const unattached = workspaceInfo.appCandidates.filter(
10089
+ (appCandidate) => !attachedProjects.includes(appCandidate)
10090
+ );
10091
+ if (unattached.length > 0) {
10092
+ console.log("");
10093
+ console.log("Other app candidates:");
10094
+ for (const appCandidate of unattached) {
10095
+ console.log(` ${appCandidate}`);
10096
+ }
10097
+ }
10098
+ return;
10099
+ }
9828
10100
  console.log(
9829
10101
  "Install Decantr at the workspace root, then attach it to the app you want Decantr to govern."
9830
10102
  );
@@ -9850,9 +10122,34 @@ function printMonorepoSetupGuidance(workspaceInfo) {
9850
10122
  ` ${cyan3(`decantr verify --project ${candidate} --base-url http://localhost:3000 --evidence`)}`
9851
10123
  );
9852
10124
  }
9853
- function resolveWorkflowProject(flags, commandName = "command") {
10125
+ function resolveWorkflowProject(flags, commandName = "command", options = {}) {
9854
10126
  const projectArg = flagString(flags, "project");
9855
10127
  const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
10128
+ if (projectArg && options.requireExisting !== false && !existsSync29(workspaceInfo.appRoot)) {
10129
+ printProjectNotFound(projectArg, commandName);
10130
+ process.exitCode = 1;
10131
+ return null;
10132
+ }
10133
+ if (projectArg && options.requireAppCandidate && workspaceInfo.appCandidates.length > 0) {
10134
+ const normalizedProject = normalizedProjectPath(projectArg);
10135
+ const knownCandidate = normalizedProject ? workspaceInfo.appCandidates.includes(normalizedProject) : false;
10136
+ const forcePackage = flagBoolean(flags, "force-package") || flagBoolean(flags, "allow-package") || flagBoolean(flags, "force");
10137
+ if (!knownCandidate && !forcePackage && !options.allowPackageProject) {
10138
+ console.error(
10139
+ error2(`decantr ${commandName} is app-scoped, but "${projectArg}" is not an app candidate.`)
10140
+ );
10141
+ if (workspaceInfo.appCandidates.length > 0) {
10142
+ console.error(dim3(`App candidates: ${workspaceInfo.appCandidates.join(", ")}`));
10143
+ }
10144
+ console.error(
10145
+ dim3(
10146
+ "Use --force-package only if you intentionally want Decantr attached to a non-app package."
10147
+ )
10148
+ );
10149
+ process.exitCode = 1;
10150
+ return null;
10151
+ }
10152
+ }
9856
10153
  if (workspaceInfo.requiresProjectSelection) {
9857
10154
  printWorkspaceProjectSelection(workspaceInfo, commandName);
9858
10155
  process.exitCode = 1;
@@ -9921,7 +10218,37 @@ async function cmdSetupWorkflow(args) {
9921
10218
  }
9922
10219
  async function cmdAdoptWorkflow(args) {
9923
10220
  const { flags } = parseLooseArgs(args);
9924
- const workspaceInfo = resolveWorkflowProject(flags, "adopt");
10221
+ if (!ensureAllowedFlags(
10222
+ flags,
10223
+ [
10224
+ "project",
10225
+ "dry-run",
10226
+ "yes",
10227
+ "y",
10228
+ "base-url",
10229
+ "verify",
10230
+ "browser",
10231
+ "evidence",
10232
+ "baseline",
10233
+ "save-baseline",
10234
+ "packs",
10235
+ "skip-packs",
10236
+ "offline",
10237
+ "ci",
10238
+ "init-ci",
10239
+ "assistant-bridge",
10240
+ "replace-essence",
10241
+ "merge-proposal",
10242
+ "telemetry",
10243
+ "force-package",
10244
+ "allow-package",
10245
+ "force"
10246
+ ],
10247
+ "adopt"
10248
+ )) {
10249
+ return;
10250
+ }
10251
+ const workspaceInfo = resolveWorkflowProject(flags, "adopt", { requireAppCandidate: true });
9925
10252
  if (!workspaceInfo) return;
9926
10253
  const projectRoot = workspaceInfo.appRoot;
9927
10254
  const projectArg = flagString(flags, "project");
@@ -9992,9 +10319,7 @@ async function cmdAdoptWorkflow(args) {
9992
10319
  )
9993
10320
  );
9994
10321
  } catch (e) {
9995
- console.log(
9996
- `${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`
9997
- );
10322
+ console.log(`${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`);
9998
10323
  console.log(
9999
10324
  dim3(
10000
10325
  `Run ${compilePacksCommandForProject(projectArg)} after adoption if you want hosted page/review packs.`
@@ -10005,7 +10330,7 @@ async function cmdAdoptWorkflow(args) {
10005
10330
  console.log(dim3("Skipping hosted pack hydration in offline mode."));
10006
10331
  }
10007
10332
  if (runVerify) {
10008
- const { cmdHealth } = await import("./health-LTDSTNOV.js");
10333
+ const { cmdHealth } = await import("./health-R7AV5G4V.js");
10009
10334
  await cmdHealth(projectRoot, {
10010
10335
  browser: runBrowser,
10011
10336
  browserBaseUrl: baseUrl,
@@ -10040,13 +10365,43 @@ async function cmdAdoptWorkflow(args) {
10040
10365
  }
10041
10366
  async function cmdVerifyWorkflow(args) {
10042
10367
  const { flags } = parseLooseArgs(args);
10368
+ const projectArg = flagString(flags, "project");
10369
+ if (!ensureAllowedFlags(
10370
+ flags,
10371
+ [
10372
+ "project",
10373
+ "workspace",
10374
+ "changed",
10375
+ "since",
10376
+ "json",
10377
+ "markdown",
10378
+ "format",
10379
+ "output",
10380
+ "ci",
10381
+ "fail-on",
10382
+ "prompt",
10383
+ "brownfield",
10384
+ "local-patterns",
10385
+ "evidence",
10386
+ "browser",
10387
+ "require-browser",
10388
+ "base-url",
10389
+ "design-tokens",
10390
+ "save-baseline",
10391
+ "since-baseline",
10392
+ "baseline"
10393
+ ],
10394
+ "verify"
10395
+ )) {
10396
+ return;
10397
+ }
10043
10398
  const workspaceMode = flagBoolean(flags, "workspace");
10044
10399
  if (args[1] === "init-ci") {
10045
10400
  await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
10046
10401
  return;
10047
10402
  }
10048
10403
  if (workspaceMode) {
10049
- const { cmdWorkspace } = await import("./workspace-53EIHUXB.js");
10404
+ const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
10050
10405
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
10051
10406
  return;
10052
10407
  }
@@ -10079,7 +10434,7 @@ async function cmdVerifyWorkflow(args) {
10079
10434
  }
10080
10435
  let guardExitCode;
10081
10436
  if (brownfield) {
10082
- const { cmdHeal, collectCheckIssues } = await import("./heal-2BDT7TR5.js");
10437
+ const { cmdHeal, collectCheckIssues } = await import("./heal-ZQHEHBUJ.js");
10083
10438
  if (quietOutput) {
10084
10439
  const result = collectCheckIssues(workspaceInfo.appRoot, { brownfield: true });
10085
10440
  guardExitCode = result.issues.some((issue) => issue.type === "error") ? 1 : void 0;
@@ -10089,7 +10444,7 @@ async function cmdVerifyWorkflow(args) {
10089
10444
  process.exitCode = void 0;
10090
10445
  }
10091
10446
  }
10092
- const { cmdHealth, parseHealthArgs } = await import("./health-LTDSTNOV.js");
10447
+ const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
10093
10448
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10094
10449
  if (localPatterns) {
10095
10450
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10097,7 +10452,7 @@ async function cmdVerifyWorkflow(args) {
10097
10452
  if (!quietOutput) {
10098
10453
  console.log("");
10099
10454
  console.log(
10100
- `${YELLOW10}Local pattern pack missing.${RESET16} Run ${cyan3("decantr codify --from-audit")}, review the proposal, then run ${cyan3("decantr codify --accept")}.`
10455
+ `${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
10456
  );
10102
10457
  }
10103
10458
  process.exitCode = process.exitCode || 1;
@@ -10159,7 +10514,7 @@ async function cmdTaskWorkflow(args) {
10159
10514
  const routeInput = positional[0];
10160
10515
  if (!routeInput) {
10161
10516
  console.error(
10162
- error3(
10517
+ error2(
10163
10518
  'Usage: decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]'
10164
10519
  )
10165
10520
  );
@@ -10172,20 +10527,20 @@ async function cmdTaskWorkflow(args) {
10172
10527
  const essence = readJsonIfPresent(essencePath);
10173
10528
  if (!essence) {
10174
10529
  console.error(
10175
- error3("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10530
+ error2("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10176
10531
  );
10177
10532
  process.exitCode = 1;
10178
10533
  return;
10179
10534
  }
10180
10535
  if (!isV49(essence)) {
10181
- console.error(error3("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10536
+ console.error(error2("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10182
10537
  process.exitCode = 1;
10183
10538
  return;
10184
10539
  }
10185
10540
  const target = essence.blueprint.routes?.[route];
10186
10541
  if (!target) {
10187
10542
  const knownRoutes = Object.keys(essence.blueprint.routes ?? {}).sort();
10188
- console.error(error3(`Route not found in Decantr contract: ${route}`));
10543
+ console.error(error2(`Route not found in Decantr contract: ${route}`));
10189
10544
  console.error(dim3(`Known routes: ${knownRoutes.join(", ") || "none"}`));
10190
10545
  process.exitCode = 1;
10191
10546
  return;
@@ -10201,6 +10556,11 @@ async function cmdTaskWorkflow(args) {
10201
10556
  const localPatternPackPath = localPatternsPath(workspaceInfo.appRoot);
10202
10557
  const localRuleManifestPath = localRulesPath(workspaceInfo.appRoot);
10203
10558
  const localLaw = createLocalLawTaskSummary(workspaceInfo.appRoot);
10559
+ const displayedLocalLaw = {
10560
+ ...localLaw,
10561
+ patternsPath: localLaw.patternsPath ? displayProjectPath(workspaceInfo, localLaw.patternsPath) : null,
10562
+ rulesPath: localLaw.rulesPath ? displayProjectPath(workspaceInfo, localLaw.rulesPath) : null
10563
+ };
10204
10564
  const changedSince = flagString(flags, "since");
10205
10565
  const currentChangedFiles = changedFiles(workspaceInfo.appRoot, changedSince);
10206
10566
  const changedRoutes = routeImpacts(workspaceInfo.appRoot, currentChangedFiles);
@@ -10212,16 +10572,16 @@ async function cmdTaskWorkflow(args) {
10212
10572
  shell: page?.shell ?? section?.shell ?? null,
10213
10573
  patterns: page?.layout?.map(extractPatternName) ?? [],
10214
10574
  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
10575
+ pagePack ? displayProjectPath(workspaceInfo, join31(".decantr/context", pagePack.markdown)) : null,
10576
+ sectionPack ? displayProjectPath(workspaceInfo, join31(".decantr/context", sectionPack.markdown)) : null,
10577
+ manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join31(".decantr/context", manifest.scaffold.markdown)) : null,
10578
+ displayProjectPath(workspaceInfo, ".decantr/context/scaffold.md"),
10579
+ displayProjectPath(workspaceInfo, "DECANTR.md"),
10580
+ existsSync29(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
10581
+ existsSync29(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null
10222
10582
  ].filter(Boolean),
10223
- screenshot: screenshot ?? null,
10224
- localLaw,
10583
+ screenshot: screenshot?.startsWith(".decantr/") ? displayProjectPath(workspaceInfo, screenshot) : screenshot ?? null,
10584
+ localLaw: displayedLocalLaw,
10225
10585
  changedFiles: currentChangedFiles,
10226
10586
  changedRoutes,
10227
10587
  verifyCommand: withProject("decantr verify --brownfield --local-patterns", projectArg)
@@ -10290,12 +10650,20 @@ async function cmdTaskWorkflow(args) {
10290
10650
  }
10291
10651
  async function cmdCodifyWorkflow(args) {
10292
10652
  const { flags } = parseLooseArgs(args);
10653
+ const projectArg = flagString(flags, "project");
10654
+ if (!ensureAllowedFlags(
10655
+ flags,
10656
+ ["project", "from-audit", "discover-local-patterns", "codify-local-patterns", "accept"],
10657
+ "codify"
10658
+ )) {
10659
+ return;
10660
+ }
10293
10661
  const workspaceInfo = resolveWorkflowProject(flags, "codify");
10294
10662
  if (!workspaceInfo) return;
10295
10663
  if (flagBoolean(flags, "accept")) {
10296
10664
  if (!existsSync29(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync29(localRulesProposalPath(workspaceInfo.appRoot))) {
10297
10665
  console.error(
10298
- error3(
10666
+ error2(
10299
10667
  "No local law proposal found. Run `decantr codify --from-audit` or `decantr codify` first."
10300
10668
  )
10301
10669
  );
@@ -10309,7 +10677,11 @@ async function cmdCodifyWorkflow(args) {
10309
10677
  if (result2.rulesAcceptedPath) {
10310
10678
  console.log(success3(`Accepted local rule manifest: ${result2.rulesAcceptedPath}`));
10311
10679
  }
10312
- console.log(dim3("Run `decantr verify --brownfield --local-patterns` after project edits."));
10680
+ console.log(
10681
+ dim3(
10682
+ `Run \`${withProject("decantr verify --brownfield --local-patterns", projectArg)}\` after project edits.`
10683
+ )
10684
+ );
10313
10685
  return;
10314
10686
  }
10315
10687
  const detected = detectProject(workspaceInfo.appRoot);
@@ -10333,7 +10705,7 @@ async function cmdCodifyWorkflow(args) {
10333
10705
  }
10334
10706
  console.log(
10335
10707
  dim3(
10336
- "Review both files, add real component paths/token recipes, then run `decantr codify --accept`."
10708
+ `Review both files, add real component paths/token recipes, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
10337
10709
  )
10338
10710
  );
10339
10711
  }
@@ -10348,10 +10720,12 @@ async function cmdContentWorkflow(args) {
10348
10720
  return;
10349
10721
  }
10350
10722
  if (subcommand === "create") {
10723
+ const { flags } = parseLooseArgs(args);
10724
+ if (!ensureAllowedFlags(flags, [], "content create")) return;
10351
10725
  const type = args[2];
10352
10726
  const name = args[3];
10353
10727
  if (!type || !name) {
10354
- console.error(error3("Usage: decantr content create <type> <name>"));
10728
+ console.error(error2("Usage: decantr content create <type> <name>"));
10355
10729
  process.exitCode = 1;
10356
10730
  return;
10357
10731
  }
@@ -10359,17 +10733,19 @@ async function cmdContentWorkflow(args) {
10359
10733
  return;
10360
10734
  }
10361
10735
  if (subcommand === "publish") {
10736
+ const { flags } = parseLooseArgs(args);
10737
+ if (!ensureAllowedFlags(flags, [], "content publish")) return;
10362
10738
  const type = args[2];
10363
10739
  const name = args[3];
10364
10740
  if (!type || !name) {
10365
- console.error(error3("Usage: decantr content publish <type> <name>"));
10741
+ console.error(error2("Usage: decantr content publish <type> <name>"));
10366
10742
  process.exitCode = 1;
10367
10743
  return;
10368
10744
  }
10369
10745
  await cmdPublish(type, name);
10370
10746
  return;
10371
10747
  }
10372
- console.error(error3("Usage: decantr content <check|create|publish>"));
10748
+ console.error(error2("Usage: decantr content <check|create|publish>"));
10373
10749
  process.exitCode = 1;
10374
10750
  }
10375
10751
  function cmdHelp() {
@@ -10905,10 +11281,10 @@ async function main() {
10905
11281
  }
10906
11282
  }
10907
11283
  }
10908
- console.error(error3("Could not resolve @decantr/cli version from package.json."));
11284
+ console.error(error2("Could not resolve @decantr/cli version from package.json."));
10909
11285
  process.exitCode = 1;
10910
11286
  } catch (e) {
10911
- console.error(error3(`Failed to read CLI version: ${e.message}`));
11287
+ console.error(error2(`Failed to read CLI version: ${e.message}`));
10912
11288
  process.exitCode = 1;
10913
11289
  }
10914
11290
  return;
@@ -10953,7 +11329,7 @@ async function main() {
10953
11329
  const newName = args[1];
10954
11330
  if (!newName) {
10955
11331
  console.error(
10956
- error3("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
11332
+ error2("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
10957
11333
  );
10958
11334
  process.exitCode = 1;
10959
11335
  break;
@@ -11025,7 +11401,10 @@ async function main() {
11025
11401
  break;
11026
11402
  }
11027
11403
  case "status": {
11028
- await cmdStatus();
11404
+ const { flags } = parseLooseArgs(args);
11405
+ const workspaceInfo = resolveWorkflowProject(flags, "status");
11406
+ if (!workspaceInfo) break;
11407
+ await cmdStatus(workspaceInfo.appRoot);
11029
11408
  break;
11030
11409
  }
11031
11410
  case "sync": {
@@ -11034,8 +11413,11 @@ async function main() {
11034
11413
  }
11035
11414
  case "upgrade": {
11036
11415
  const { cmdUpgrade } = await import("./upgrade-VON7Y3LG.js");
11416
+ const { flags } = parseLooseArgs(args);
11417
+ const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
11418
+ if (!workspaceInfo) break;
11037
11419
  const applyFlag = args.includes("--apply");
11038
- await cmdUpgrade(process.cwd(), { apply: applyFlag });
11420
+ await cmdUpgrade(workspaceInfo.appRoot, { apply: applyFlag });
11039
11421
  break;
11040
11422
  }
11041
11423
  case "check":
@@ -11045,13 +11427,16 @@ async function main() {
11045
11427
  `${YELLOW10}Note: \`decantr heal\` is deprecated. Use \`decantr check\` instead.${RESET16}`
11046
11428
  );
11047
11429
  }
11048
- const { cmdHeal } = await import("./heal-2BDT7TR5.js");
11430
+ const { cmdHeal } = await import("./heal-ZQHEHBUJ.js");
11049
11431
  const { flags } = parseLooseArgs(args);
11050
11432
  const workspaceInfo = resolveWorkflowProject(flags, "check");
11051
11433
  if (!workspaceInfo) break;
11052
11434
  const telemetryFlag = args.includes("--telemetry");
11053
11435
  const brownfieldFlag = args.includes("--brownfield");
11054
- await cmdHeal(workspaceInfo.appRoot, { telemetry: telemetryFlag, brownfield: brownfieldFlag });
11436
+ await cmdHeal(workspaceInfo.appRoot, {
11437
+ telemetry: telemetryFlag,
11438
+ brownfield: brownfieldFlag
11439
+ });
11055
11440
  break;
11056
11441
  }
11057
11442
  case "health": {
@@ -11060,10 +11445,17 @@ async function main() {
11060
11445
  cmdHealthHelp();
11061
11446
  break;
11062
11447
  }
11063
- const { cmdHealth, parseHealthArgs } = await import("./health-LTDSTNOV.js");
11064
- await cmdHealth(process.cwd(), parseHealthArgs(args));
11448
+ if (args[1] === "init-ci") {
11449
+ await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
11450
+ break;
11451
+ }
11452
+ const { flags } = parseLooseArgs(args);
11453
+ const workspaceInfo = resolveWorkflowProject(flags, "health");
11454
+ if (!workspaceInfo) break;
11455
+ const { cmdHealth, parseHealthArgs } = await import("./health-R7AV5G4V.js");
11456
+ await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
11065
11457
  } catch (e) {
11066
- console.error(error3(e.message));
11458
+ console.error(error2(e.message));
11067
11459
  process.exitCode = 1;
11068
11460
  }
11069
11461
  break;
@@ -11077,7 +11469,7 @@ async function main() {
11077
11469
  const { cmdContentHealth, parseContentHealthArgs } = await import("./content-health-4KP2EGTI.js");
11078
11470
  await cmdContentHealth(process.cwd(), parseContentHealthArgs(args));
11079
11471
  } catch (e) {
11080
- console.error(error3(e.message));
11472
+ console.error(error2(e.message));
11081
11473
  process.exitCode = 1;
11082
11474
  }
11083
11475
  break;
@@ -11088,10 +11480,10 @@ async function main() {
11088
11480
  cmdStudioHelp();
11089
11481
  break;
11090
11482
  }
11091
- const { cmdStudio, parseStudioArgs } = await import("./studio-7E2LJS3A.js");
11483
+ const { cmdStudio, parseStudioArgs } = await import("./studio-2734P63C.js");
11092
11484
  await cmdStudio(process.cwd(), parseStudioArgs(args));
11093
11485
  } catch (e) {
11094
- console.error(error3(e.message));
11486
+ console.error(error2(e.message));
11095
11487
  process.exitCode = 1;
11096
11488
  }
11097
11489
  break;
@@ -11102,10 +11494,10 @@ async function main() {
11102
11494
  cmdWorkspaceHelp();
11103
11495
  break;
11104
11496
  }
11105
- const { cmdWorkspace } = await import("./workspace-53EIHUXB.js");
11497
+ const { cmdWorkspace } = await import("./workspace-DRHTQ2NG.js");
11106
11498
  await cmdWorkspace(process.cwd(), args);
11107
11499
  } catch (e) {
11108
- console.error(error3(e.message));
11500
+ console.error(error2(e.message));
11109
11501
  process.exitCode = 1;
11110
11502
  }
11111
11503
  break;
@@ -11128,7 +11520,7 @@ async function main() {
11128
11520
  if (result.success) {
11129
11521
  console.log(success3(clearFlag ? "Drift log cleared." : "Entries resolved."));
11130
11522
  } else {
11131
- console.error(error3(result.error || "Failed"));
11523
+ console.error(error2(result.error || "Failed"));
11132
11524
  process.exitCode = 1;
11133
11525
  }
11134
11526
  } else {
@@ -11144,7 +11536,7 @@ async function main() {
11144
11536
  const query = args[1];
11145
11537
  if (!query) {
11146
11538
  console.error(
11147
- error3(
11539
+ error2(
11148
11540
  "Usage: decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11149
11541
  )
11150
11542
  );
@@ -11162,7 +11554,7 @@ async function main() {
11162
11554
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11163
11555
  if (rawBlueprintSet && !blueprintSet) {
11164
11556
  console.error(
11165
- error3(
11557
+ error2(
11166
11558
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11167
11559
  )
11168
11560
  );
@@ -11171,7 +11563,7 @@ async function main() {
11171
11563
  }
11172
11564
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11173
11565
  console.error(
11174
- error3(
11566
+ error2(
11175
11567
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11176
11568
  )
11177
11569
  );
@@ -11183,31 +11575,51 @@ async function main() {
11183
11575
  break;
11184
11576
  }
11185
11577
  case "suggest": {
11186
- const query = args[1];
11578
+ const { flags, positional } = parseLooseArgs(args);
11579
+ if (!ensureAllowedFlags(flags, ["type", "route", "file", "from-code", "project"], "suggest")) {
11580
+ break;
11581
+ }
11582
+ const projectArg = flagString(flags, "project");
11583
+ const route = flagString(flags, "route");
11584
+ let file = flagString(flags, "file");
11585
+ const normalizedProject = normalizedProjectPath(projectArg);
11586
+ if (file && normalizedProject && normalizedProjectPath(file)?.startsWith(`${normalizedProject}/`)) {
11587
+ file = normalizedProjectPath(file)?.slice(normalizedProject.length + 1);
11588
+ }
11589
+ const fromCode = flagBoolean(flags, "from-code");
11590
+ let query = positional.join(" ").trim();
11591
+ if (!query && (route || file || fromCode)) {
11592
+ query = [
11593
+ route ? `route ${route}` : null,
11594
+ file ? `file ${basename3(file)}` : null,
11595
+ fromCode ? "source code patterns" : null
11596
+ ].filter((entry) => Boolean(entry)).join(" ");
11597
+ }
11187
11598
  if (!query) {
11188
11599
  console.error(
11189
- error3(
11190
- "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code]"
11600
+ error2(
11601
+ "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code] [--project <path>]"
11191
11602
  )
11192
11603
  );
11193
11604
  process.exitCode = 1;
11194
11605
  return;
11195
11606
  }
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 });
11607
+ const workspaceInfo = projectArg ? resolveWorkflowProject(flags, "suggest") : null;
11608
+ if (projectArg && !workspaceInfo) break;
11609
+ await cmdSuggest(query, {
11610
+ type: flagString(flags, "type"),
11611
+ route,
11612
+ file,
11613
+ fromCode,
11614
+ projectRoot: workspaceInfo?.appRoot
11615
+ });
11204
11616
  break;
11205
11617
  }
11206
11618
  case "get": {
11207
11619
  const type = args[1];
11208
11620
  const id = args[2];
11209
11621
  if (!type || !id) {
11210
- console.error(error3("Usage: decantr get <type> <id>"));
11622
+ console.error(error2("Usage: decantr get <type> <id>"));
11211
11623
  process.exitCode = 1;
11212
11624
  return;
11213
11625
  }
@@ -11218,7 +11630,7 @@ async function main() {
11218
11630
  const type = args[1];
11219
11631
  if (!type) {
11220
11632
  console.error(
11221
- error3(
11633
+ error2(
11222
11634
  "Usage: decantr list <type> [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11223
11635
  )
11224
11636
  );
@@ -11234,7 +11646,7 @@ async function main() {
11234
11646
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11235
11647
  if (rawBlueprintSet && !blueprintSet) {
11236
11648
  console.error(
11237
- error3(
11649
+ error2(
11238
11650
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11239
11651
  )
11240
11652
  );
@@ -11243,7 +11655,7 @@ async function main() {
11243
11655
  }
11244
11656
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11245
11657
  console.error(
11246
- error3(
11658
+ error2(
11247
11659
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11248
11660
  )
11249
11661
  );
@@ -11263,7 +11675,7 @@ async function main() {
11263
11675
  break;
11264
11676
  }
11265
11677
  if (requestedView && !["manifest", "shortlist", "verification"].includes(requestedView)) {
11266
- console.error(error3("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11678
+ console.error(error2("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11267
11679
  process.exitCode = 1;
11268
11680
  break;
11269
11681
  }
@@ -11275,7 +11687,10 @@ async function main() {
11275
11687
  break;
11276
11688
  }
11277
11689
  case "theme": {
11278
- await cmdTheme(args.slice(1));
11690
+ const { flags } = parseLooseArgs(args);
11691
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "theme") : null;
11692
+ if (flagString(flags, "project") && !workspaceInfo) break;
11693
+ await cmdTheme(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11279
11694
  break;
11280
11695
  }
11281
11696
  case "login": {
@@ -11309,14 +11724,19 @@ async function main() {
11309
11724
  break;
11310
11725
  }
11311
11726
  case "telemetry": {
11312
- await cmdTelemetry(args.slice(1), process.cwd());
11727
+ const { flags } = parseLooseArgs(args);
11728
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "telemetry") : null;
11729
+ if (flagString(flags, "project") && !workspaceInfo) break;
11730
+ await cmdTelemetry(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11313
11731
  break;
11314
11732
  }
11315
11733
  case "create": {
11734
+ const { flags } = parseLooseArgs(args);
11735
+ if (!ensureAllowedFlags(flags, [], "create")) break;
11316
11736
  const type = args[1];
11317
11737
  const name = args[2];
11318
11738
  if (!type || !name) {
11319
- console.error(error3("Usage: decantr create <type> <name>"));
11739
+ console.error(error2("Usage: decantr create <type> <name>"));
11320
11740
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11321
11741
  process.exitCode = 1;
11322
11742
  break;
@@ -11325,10 +11745,12 @@ async function main() {
11325
11745
  break;
11326
11746
  }
11327
11747
  case "publish": {
11748
+ const { flags } = parseLooseArgs(args);
11749
+ if (!ensureAllowedFlags(flags, [], "publish")) break;
11328
11750
  const type = args[1];
11329
11751
  const name = args[2];
11330
11752
  if (!type || !name) {
11331
- console.error(error3("Usage: decantr publish <type> <name>"));
11753
+ console.error(error2("Usage: decantr publish <type> <name>"));
11332
11754
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11333
11755
  process.exitCode = 1;
11334
11756
  break;
@@ -11345,7 +11767,8 @@ async function main() {
11345
11767
  offline: refreshOffline,
11346
11768
  check: args.includes("--check"),
11347
11769
  listChanges: args.includes("--list-changes"),
11348
- json: args.includes("--json")
11770
+ json: args.includes("--json"),
11771
+ displayRoot: workspaceInfo.cwd
11349
11772
  });
11350
11773
  break;
11351
11774
  }
@@ -11380,7 +11803,7 @@ async function main() {
11380
11803
  let id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
11381
11804
  if (!packType || !["manifest", "scaffold", "review", "section", "page", "mutation"].includes(packType)) {
11382
11805
  console.error(
11383
- `${RED13}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11806
+ `${RED12}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11384
11807
  );
11385
11808
  process.exitCode = 1;
11386
11809
  break;
@@ -11412,7 +11835,7 @@ async function main() {
11412
11835
  const sourcePath = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
11413
11836
  if (!sourcePath) {
11414
11837
  console.error(
11415
- `${RED13}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11838
+ `${RED12}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11416
11839
  );
11417
11840
  process.exitCode = 1;
11418
11841
  break;
@@ -11437,16 +11860,20 @@ async function main() {
11437
11860
  await printHostedProjectAudit(namespace, jsonOutput, essencePath, distPath, sourcesPath);
11438
11861
  } else {
11439
11862
  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}`
11863
+ `${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
11864
  );
11442
11865
  process.exitCode = 1;
11443
11866
  }
11444
11867
  break;
11445
11868
  }
11446
11869
  case "add": {
11870
+ const { flags } = parseLooseArgs(args);
11871
+ if (!ensureAllowedFlags(flags, ["project", "route", "section"], "add")) break;
11872
+ const workspaceInfo = resolveWorkflowProject(flags, "add");
11873
+ if (!workspaceInfo) break;
11447
11874
  const subcommand = args[1];
11448
11875
  if (!subcommand) {
11449
- console.error(error3("Usage: decantr add <section|page|feature> <target>"));
11876
+ console.error(error2("Usage: decantr add <section|page|feature> <target>"));
11450
11877
  process.exitCode = 1;
11451
11878
  break;
11452
11879
  }
@@ -11454,45 +11881,49 @@ async function main() {
11454
11881
  case "section": {
11455
11882
  const id = args[2];
11456
11883
  if (!id) {
11457
- console.error(error3("Usage: decantr add section <archetypeId>"));
11884
+ console.error(error2("Usage: decantr add section <archetypeId>"));
11458
11885
  process.exitCode = 1;
11459
11886
  break;
11460
11887
  }
11461
- await cmdAddSection(id, args, process.cwd());
11888
+ await cmdAddSection(id, args, workspaceInfo.appRoot);
11462
11889
  break;
11463
11890
  }
11464
11891
  case "page": {
11465
11892
  const pagePath = args[2];
11466
11893
  if (!pagePath) {
11467
- console.error(error3("Usage: decantr add page <section>/<page>"));
11894
+ console.error(error2("Usage: decantr add page <section>/<page>"));
11468
11895
  process.exitCode = 1;
11469
11896
  break;
11470
11897
  }
11471
- await cmdAddPage(pagePath, args, process.cwd());
11898
+ await cmdAddPage(pagePath, args, workspaceInfo.appRoot);
11472
11899
  break;
11473
11900
  }
11474
11901
  case "feature": {
11475
11902
  const feature = args[2];
11476
11903
  if (!feature) {
11477
- console.error(error3("Usage: decantr add feature <feature> [--section <id>]"));
11904
+ console.error(error2("Usage: decantr add feature <feature> [--section <id>]"));
11478
11905
  process.exitCode = 1;
11479
11906
  break;
11480
11907
  }
11481
- await cmdAddFeature(feature, args, process.cwd());
11908
+ await cmdAddFeature(feature, args, workspaceInfo.appRoot);
11482
11909
  break;
11483
11910
  }
11484
11911
  default:
11485
11912
  console.error(
11486
- error3(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11913
+ error2(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11487
11914
  );
11488
11915
  process.exitCode = 1;
11489
11916
  }
11490
11917
  break;
11491
11918
  }
11492
11919
  case "remove": {
11920
+ const { flags } = parseLooseArgs(args);
11921
+ if (!ensureAllowedFlags(flags, ["project", "section"], "remove")) break;
11922
+ const workspaceInfo = resolveWorkflowProject(flags, "remove");
11923
+ if (!workspaceInfo) break;
11493
11924
  const subcommand = args[1];
11494
11925
  if (!subcommand) {
11495
- console.error(error3("Usage: decantr remove <section|page|feature> <target>"));
11926
+ console.error(error2("Usage: decantr remove <section|page|feature> <target>"));
11496
11927
  process.exitCode = 1;
11497
11928
  break;
11498
11929
  }
@@ -11500,56 +11931,54 @@ async function main() {
11500
11931
  case "section": {
11501
11932
  const id = args[2];
11502
11933
  if (!id) {
11503
- console.error(error3("Usage: decantr remove section <sectionId>"));
11934
+ console.error(error2("Usage: decantr remove section <sectionId>"));
11504
11935
  process.exitCode = 1;
11505
11936
  break;
11506
11937
  }
11507
- await cmdRemoveSection(id, args, process.cwd());
11938
+ await cmdRemoveSection(id, args, workspaceInfo.appRoot);
11508
11939
  break;
11509
11940
  }
11510
11941
  case "page": {
11511
11942
  const pagePath = args[2];
11512
11943
  if (!pagePath) {
11513
- console.error(error3("Usage: decantr remove page <section>/<page>"));
11944
+ console.error(error2("Usage: decantr remove page <section>/<page>"));
11514
11945
  process.exitCode = 1;
11515
11946
  break;
11516
11947
  }
11517
- await cmdRemovePage(pagePath, args, process.cwd());
11948
+ await cmdRemovePage(pagePath, args, workspaceInfo.appRoot);
11518
11949
  break;
11519
11950
  }
11520
11951
  case "feature": {
11521
11952
  const feature = args[2];
11522
11953
  if (!feature) {
11523
- console.error(error3("Usage: decantr remove feature <feature> [--section <id>]"));
11954
+ console.error(error2("Usage: decantr remove feature <feature> [--section <id>]"));
11524
11955
  process.exitCode = 1;
11525
11956
  break;
11526
11957
  }
11527
- await cmdRemoveFeature(feature, args, process.cwd());
11958
+ await cmdRemoveFeature(feature, args, workspaceInfo.appRoot);
11528
11959
  break;
11529
11960
  }
11530
11961
  default:
11531
11962
  console.error(
11532
- error3(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11963
+ error2(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11533
11964
  );
11534
11965
  process.exitCode = 1;
11535
11966
  }
11536
11967
  break;
11537
11968
  }
11538
11969
  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;
11970
+ const { flags } = parseLooseArgs(args);
11971
+ if (!ensureAllowedFlags(
11972
+ flags,
11973
+ ["project", "force-package", "allow-package", "force"],
11974
+ "analyze"
11975
+ )) {
11551
11976
  break;
11552
11977
  }
11978
+ const workspaceInfo = resolveWorkflowProject(flags, "analyze", {
11979
+ requireAppCandidate: true
11980
+ });
11981
+ if (!workspaceInfo) break;
11553
11982
  await cmdAnalyze(workspaceInfo.appRoot, workspaceInfo);
11554
11983
  break;
11555
11984
  }
@@ -11560,24 +11989,14 @@ async function main() {
11560
11989
  break;
11561
11990
  }
11562
11991
  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");
11992
+ console.error(error2("Usage: decantr rules <preview|apply> [--project=<path>]"));
11578
11993
  process.exitCode = 1;
11579
11994
  break;
11580
11995
  }
11996
+ const { flags } = parseLooseArgs(args);
11997
+ if (!ensureAllowedFlags(flags, ["project"], "rules")) break;
11998
+ const workspaceInfo = resolveWorkflowProject(flags, "rules");
11999
+ if (!workspaceInfo) break;
11581
12000
  const detected = detectProject(workspaceInfo.appRoot);
11582
12001
  if (subcommand === "preview") {
11583
12002
  console.log(
@@ -11598,24 +12017,18 @@ async function main() {
11598
12017
  break;
11599
12018
  }
11600
12019
  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
- }
12020
+ const { flags, positional } = parseLooseArgs(args);
12021
+ if (!ensureAllowedFlags(flags, ["dry-run", "offline", "registry", "project"], "magic")) {
12022
+ break;
11615
12023
  }
11616
- const magicPrompt = promptParts.join(" ").trim();
12024
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "magic") : null;
12025
+ if (flagString(flags, "project") && !workspaceInfo) break;
12026
+ const projectArg = flagString(flags, "project");
12027
+ const magicPrompt = positional.join(" ").trim();
11617
12028
  if (!magicPrompt) {
11618
- console.error(error3("Usage: decantr magic <prompt> [--dry-run] [--offline]"));
12029
+ console.error(
12030
+ error2("Usage: decantr magic <prompt> [--dry-run] [--offline] [--project <path>]")
12031
+ );
11619
12032
  console.error("");
11620
12033
  console.error(" Example:");
11621
12034
  console.error(
@@ -11624,38 +12037,34 @@ async function main() {
11624
12037
  process.exitCode = 1;
11625
12038
  break;
11626
12039
  }
11627
- await cmdMagic(magicPrompt, process.cwd(), {
11628
- dryRun: magicFlags.dryRun,
11629
- offline: magicFlags.offline,
11630
- registry: magicFlags.registry
12040
+ await cmdMagic(magicPrompt, workspaceInfo?.appRoot ?? process.cwd(), {
12041
+ dryRun: flagBoolean(flags, "dry-run"),
12042
+ offline: flagBoolean(flags, "offline"),
12043
+ registry: flagString(flags, "registry"),
12044
+ projectLabel: projectArg
11631
12045
  });
11632
12046
  break;
11633
12047
  }
11634
12048
  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
- }
12049
+ const { flags } = parseLooseArgs(args);
12050
+ if (!ensureAllowedFlags(flags, ["to", "output", "project"], "export")) break;
12051
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "export") : null;
12052
+ if (flagString(flags, "project") && !workspaceInfo) break;
12053
+ const exportTarget = flagString(flags, "to");
12054
+ const exportOutput = flagString(flags, "output");
11648
12055
  const validTargets = ["shadcn", "tailwind", "css-vars", "figma-tokens"];
11649
12056
  if (!exportTarget || !validTargets.includes(exportTarget)) {
11650
- console.error(error3(`Usage: decantr export --to <${validTargets.join("|")}>`));
12057
+ console.error(error2(`Usage: decantr export --to <${validTargets.join("|")}>`));
11651
12058
  process.exitCode = 1;
11652
12059
  break;
11653
12060
  }
11654
- await cmdExport(exportTarget, process.cwd(), { output: exportOutput });
12061
+ await cmdExport(exportTarget, workspaceInfo?.appRoot ?? process.cwd(), {
12062
+ output: exportOutput
12063
+ });
11655
12064
  break;
11656
12065
  }
11657
12066
  default:
11658
- console.error(error3(`Unknown command: ${command}`));
12067
+ console.error(error2(`Unknown command: ${command}`));
11659
12068
  cmdHelp();
11660
12069
  process.exitCode = 1;
11661
12070
  }
@@ -11670,7 +12079,7 @@ main().then(async () => {
11670
12079
  success: !process.exitCode || process.exitCode === 0
11671
12080
  });
11672
12081
  }).catch(async (e) => {
11673
- console.error(error3(e.message));
12082
+ console.error(error2(e.message));
11674
12083
  if (e.stack) console.error(e.stack);
11675
12084
  process.exitCode = 1;
11676
12085
  await sendCliCommandTelemetry({