@decantr/cli 2.9.1 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,15 +21,15 @@ import {
21
21
  formatWorkspaceHealthText,
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
- resolveWorkspaceInfo,
25
24
  shouldFailWorkspaceHealth
26
- } from "./chunk-FKM4OQDF.js";
25
+ } from "./chunk-ARR3EPS2.js";
27
26
  import {
28
27
  createProjectHealthReport,
29
28
  formatProjectHealthMarkdown,
30
29
  formatProjectHealthText,
30
+ resolveWorkspaceInfo,
31
31
  shouldFailHealth
32
- } from "./chunk-TMOCTDYY.js";
32
+ } from "./chunk-XZFKK6V7.js";
33
33
  import {
34
34
  buildGuardRegistryContext,
35
35
  createDoctrineMap,
@@ -50,7 +50,7 @@ import {
50
50
 
51
51
  // src/index.ts
52
52
  import { existsSync as existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync9, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "fs";
53
- import { basename as basename3, dirname as dirname5, isAbsolute, join as join31, resolve as resolve4 } from "path";
53
+ import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute3, join as join31, relative as relative7, resolve as resolve4 } from "path";
54
54
  import { fileURLToPath as fileURLToPath3 } from "url";
55
55
  import { evaluateGuard, isV4 as isV49, validateEssence as validateEssence2 } from "@decantr/essence-spec";
56
56
  import {
@@ -1772,6 +1772,20 @@ function readV4Essence(projectRoot) {
1772
1772
  function writeEssence(essencePath, essence) {
1773
1773
  writeFileSync6(essencePath, JSON.stringify(essence, null, 2) + "\n");
1774
1774
  }
1775
+ function readFlagValue(args, name) {
1776
+ const prefix = `--${name}=`;
1777
+ for (let index = 0; index < args.length; index += 1) {
1778
+ const arg = args[index];
1779
+ if (arg === `--${name}` && args[index + 1]) return args[index + 1];
1780
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
1781
+ }
1782
+ return void 0;
1783
+ }
1784
+ function normalizeRoute(route) {
1785
+ const trimmed = route.trim();
1786
+ if (!trimmed || trimmed === "/") return "/";
1787
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
1788
+ }
1775
1789
  async function cmdAddSection(archetypeId, args, projectRoot = process.cwd()) {
1776
1790
  if (!archetypeId) {
1777
1791
  console.error(`${RED}Usage: decantr add section <archetypeId>${RESET}`);
@@ -1847,12 +1861,27 @@ async function cmdAddPage(path, args, projectRoot = process.cwd()) {
1847
1861
  process.exitCode = 1;
1848
1862
  return;
1849
1863
  }
1864
+ const route = normalizeRoute(readFlagValue(args, "route") ?? pageId);
1865
+ const routes = essence.blueprint.routes ??= {};
1866
+ const existingRoute = routes[route];
1867
+ if (existingRoute) {
1868
+ console.error(
1869
+ `${RED}Route "${route}" already maps to ${existingRoute.section}/${existingRoute.page}.${RESET}`
1870
+ );
1871
+ console.error(`${DIM}Pass a unique route with --route /some-path.${RESET}`);
1872
+ process.exitCode = 1;
1873
+ return;
1874
+ }
1850
1875
  section.pages.push({
1851
1876
  id: pageId,
1877
+ route,
1852
1878
  layout: ["hero"]
1853
1879
  });
1880
+ routes[route] = { section: sectionId, page: pageId };
1854
1881
  writeEssence(essencePath, essence);
1855
- console.log(`${GREEN}Added page "${pageId}" to section "${sectionId}".${RESET}`);
1882
+ console.log(
1883
+ `${GREEN}Added page "${pageId}" to section "${sectionId}" at route "${route}".${RESET}`
1884
+ );
1856
1885
  const registryClient = new RegistryClient({
1857
1886
  cacheDir: join6(projectRoot, ".decantr", "cache")
1858
1887
  });
@@ -1869,10 +1898,7 @@ async function cmdAddFeature(feature, args, projectRoot = process.cwd()) {
1869
1898
  if (!loaded) return;
1870
1899
  const { essence, essencePath } = loaded;
1871
1900
  let sectionId;
1872
- const sectionIdx = args.indexOf("--section");
1873
- if (sectionIdx !== -1 && args[sectionIdx + 1]) {
1874
- sectionId = args[sectionIdx + 1];
1875
- }
1901
+ sectionId = readFlagValue(args, "section");
1876
1902
  if (sectionId) {
1877
1903
  const sections = essence.blueprint.sections;
1878
1904
  const section = sections.find((s) => s.id === sectionId);
@@ -1901,7 +1927,7 @@ async function cmdAddFeature(feature, args, projectRoot = process.cwd()) {
1901
1927
 
1902
1928
  // src/commands/analyze.ts
1903
1929
  import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
1904
- import { join as join14 } from "path";
1930
+ import { join as join14, relative as relative2 } from "path";
1905
1931
 
1906
1932
  // src/analyzers/components.ts
1907
1933
  import { existsSync as existsSync5, readdirSync, statSync as statSync2 } from "fs";
@@ -2957,6 +2983,10 @@ ${BOLD}Analyzing project...${RESET2}
2957
2983
  const doctrine = createDoctrineMap(ambient);
2958
2984
  const initSeed = createBrownfieldInitSeed(project, layout, styling);
2959
2985
  initSeed.projectScope = workspace?.projectScope ?? "single-app";
2986
+ const projectLabel = workspace && workspace.appRoot !== workspace.workspaceRoot ? relative2(workspace.workspaceRoot, workspace.appRoot).replace(/\\/g, "/") : null;
2987
+ const projectFlag = projectLabel ? ` --project ${projectLabel}` : "";
2988
+ const reportDisplayPath = projectLabel ? `${projectLabel}/.decantr/brownfield-report.md` : ".decantr/brownfield-report.md";
2989
+ const recommendedAttachCommand = `decantr init${projectFlag} --existing --accept-proposal`;
2960
2990
  const proposal = createBrownfieldProposal({
2961
2991
  project,
2962
2992
  routes,
@@ -2996,7 +3026,7 @@ ${BOLD}Analyzing project...${RESET2}
2996
3026
  adoptionMode: "contract-only",
2997
3027
  initSeedPath: ".decantr/init-seed.json",
2998
3028
  proposalPath: ".decantr/observed-essence.proposal.json",
2999
- recommendedCommand: "decantr init --existing --accept-proposal"
3029
+ recommendedCommand: recommendedAttachCommand
3000
3030
  },
3001
3031
  hybrid: {
3002
3032
  ownerCommands: [
@@ -3096,7 +3126,7 @@ ${DIM2}Written to:${RESET2} ${outputPath}`);
3096
3126
  console.log(`${DIM2}Enrichment backlog:${RESET2} ${intelligenceArtifacts.backlogPath}`);
3097
3127
  console.log(
3098
3128
  `
3099
- ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2}, then run ${BOLD}decantr init --existing --accept-proposal${RESET2} to attach Decantr using the observed proposal.
3129
+ ${YELLOW}Next step:${RESET2} Review ${BOLD}${reportDisplayPath}${RESET2}, then run ${BOLD}${recommendedAttachCommand}${RESET2} to attach Decantr using the observed proposal.
3100
3130
  `
3101
3131
  );
3102
3132
  await sendAnalyzeCompletedTelemetry({
@@ -3119,12 +3149,12 @@ ${YELLOW}Next step:${RESET2} Review ${BOLD}.decantr/brownfield-report.md${RESET2
3119
3149
 
3120
3150
  // src/commands/ci.ts
3121
3151
  import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
3122
- import { dirname as dirname2, join as join16, relative as relative3, resolve } from "path";
3152
+ import { dirname as dirname2, join as join16, relative as relative4, resolve } from "path";
3123
3153
 
3124
3154
  // src/local-law.ts
3125
3155
  import { execFileSync } from "child_process";
3126
3156
  import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync5, writeFileSync as writeFileSync9 } from "fs";
3127
- import { basename as basename2, extname, join as join15, relative as relative2, sep } from "path";
3157
+ import { basename as basename2, extname, join as join15, relative as relative3, sep } from "path";
3128
3158
  import { isV4 as isV43 } from "@decantr/essence-spec";
3129
3159
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
3130
3160
  ".astro",
@@ -3565,7 +3595,7 @@ function listSourceFiles(projectRoot, maxFiles) {
3565
3595
  if (stat.isDirectory()) {
3566
3596
  visit(absolute);
3567
3597
  } else if (stat.isFile() && SOURCE_EXTENSIONS.has(extname(entry))) {
3568
- files.push({ absolute, relative: normalizePath(relative2(projectRoot, absolute)) });
3598
+ files.push({ absolute, relative: normalizePath(relative3(projectRoot, absolute)) });
3569
3599
  }
3570
3600
  }
3571
3601
  };
@@ -3653,7 +3683,8 @@ function parseCiArgs(args) {
3653
3683
  return options;
3654
3684
  }
3655
3685
  function parseProvider(value) {
3656
- return value === "generic" ? "generic" : "github";
3686
+ if (value === "github" || value === "generic") return value;
3687
+ throw new Error("Invalid --provider value. Use github or generic.");
3657
3688
  }
3658
3689
  function detectPackageManager(root) {
3659
3690
  const pkg = readJson(join16(root, "package.json"));
@@ -3667,6 +3698,12 @@ function detectPackageManager(root) {
3667
3698
  if (existsSync14(join16(root, "bun.lock")) || existsSync14(join16(root, "bun.lockb"))) return "bun";
3668
3699
  return "unknown";
3669
3700
  }
3701
+ function hasWorkspaceMarker(root) {
3702
+ const pkg = readJson(join16(root, "package.json"));
3703
+ return Boolean(
3704
+ existsSync14(join16(root, "pnpm-workspace.yaml")) || existsSync14(join16(root, "turbo.json")) || existsSync14(join16(root, "nx.json")) || pkg?.workspaces
3705
+ );
3706
+ }
3670
3707
  function installCommand(packageManager) {
3671
3708
  switch (packageManager) {
3672
3709
  case "pnpm":
@@ -3681,6 +3718,20 @@ function installCommand(packageManager) {
3681
3718
  return "npm install";
3682
3719
  }
3683
3720
  }
3721
+ function pinCliCommand(packageManager, root) {
3722
+ switch (packageManager) {
3723
+ case "pnpm":
3724
+ return hasWorkspaceMarker(root) ? "pnpm add -D -w @decantr/cli" : "pnpm add -D @decantr/cli";
3725
+ case "yarn":
3726
+ return "yarn add -D @decantr/cli";
3727
+ case "bun":
3728
+ return "bun add -d @decantr/cli";
3729
+ case "npm":
3730
+ return "npm install -D @decantr/cli";
3731
+ default:
3732
+ return "npm install -D @decantr/cli";
3733
+ }
3734
+ }
3684
3735
  function decantrCommand(packageManager) {
3685
3736
  switch (packageManager) {
3686
3737
  case "pnpm":
@@ -3823,6 +3874,9 @@ jobs:
3823
3874
  }
3824
3875
  function writeCiInit(root, options) {
3825
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
+ }
3826
3880
  if (workspaceInfo.requiresProjectSelection && !options.workspace) {
3827
3881
  const candidate = workspaceInfo.appCandidates[0] ?? "apps/web";
3828
3882
  throw new Error(
@@ -3830,14 +3884,14 @@ function writeCiInit(root, options) {
3830
3884
  );
3831
3885
  }
3832
3886
  const outputRoot = workspaceInfo.workspaceRoot;
3833
- 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, "/"));
3834
3888
  const packageManager = detectPackageManager(outputRoot);
3835
3889
  const command = decantrCommand(packageManager);
3836
3890
  const failOn = options.failOn ?? "error";
3837
3891
  const provider = options.provider ?? "github";
3838
3892
  if (!localCliPinned(outputRoot)) {
3839
3893
  console.log(
3840
- `${DIM3}No @decantr/cli dependency was found in the workspace root package.json. The generated command still uses the local package-manager binary path; pin @decantr/cli in devDependencies before relying on CI.${RESET3}`
3894
+ `${DIM3}No @decantr/cli dependency was found in the workspace root package.json. Before relying on CI, pin it with: ${pinCliCommand(packageManager, outputRoot)}${RESET3}`
3841
3895
  );
3842
3896
  }
3843
3897
  if (provider === "generic") {
@@ -3913,6 +3967,10 @@ async function runWorkspaceCi(root, options) {
3913
3967
  }
3914
3968
  async function runProjectCi(root, options) {
3915
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
+ }
3916
3974
  if (workspaceInfo.requiresProjectSelection) {
3917
3975
  const candidate = workspaceInfo.appCandidates[0] ?? "apps/web";
3918
3976
  console.error(`${RED2}Decantr CI needs an app path in this monorepo.${RESET3}`);
@@ -3963,16 +4021,16 @@ ${BOLD2}Examples:${RESET3}
3963
4021
  `);
3964
4022
  }
3965
4023
  async function cmdCi(args = ["ci"], root = process.cwd()) {
3966
- const options = parseCiArgs(args);
3967
4024
  try {
4025
+ const options = parseCiArgs(args);
3968
4026
  if (options.init) {
3969
4027
  writeCiInit(root, options);
3970
4028
  return;
3971
4029
  }
3972
4030
  const exitCode = options.workspace ? await runWorkspaceCi(root, options) : await runProjectCi(root, options);
3973
4031
  if (exitCode !== 0) process.exitCode = exitCode;
3974
- } catch (error4) {
3975
- console.error(`${RED2}${error4.message}${RESET3}`);
4032
+ } catch (error3) {
4033
+ console.error(`${RED2}${error3.message}${RESET3}`);
3976
4034
  process.exitCode = 1;
3977
4035
  }
3978
4036
  }
@@ -4191,7 +4249,7 @@ function cmdCreate(type, name, projectRoot = process.cwd()) {
4191
4249
 
4192
4250
  // src/commands/doctor.ts
4193
4251
  import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
4194
- 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";
4195
4253
  import { fileURLToPath } from "url";
4196
4254
  import { isV4 as isV44 } from "@decantr/essence-spec";
4197
4255
  import { collectMissingPackManifestFiles } from "@decantr/verifier";
@@ -4210,6 +4268,10 @@ function readJson2(path) {
4210
4268
  return null;
4211
4269
  }
4212
4270
  }
4271
+ function isContractOnlyProject(projectRoot) {
4272
+ const projectJson = readJson2(join18(projectRoot, ".decantr", "project.json"));
4273
+ return projectJson?.initialized?.adoptionMode === "contract-only";
4274
+ }
4213
4275
  function readCliPackageVersion() {
4214
4276
  const packagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "..", "package.json");
4215
4277
  const srcPackagePath = join18(dirname3(fileURLToPath(import.meta.url)), "..", "package.json");
@@ -4235,8 +4297,28 @@ function localCliDependency(root) {
4235
4297
  const pkg = readPackageJson(root);
4236
4298
  return pkg?.devDependencies?.["@decantr/cli"] ?? pkg?.dependencies?.["@decantr/cli"] ?? null;
4237
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
+ }
4238
4320
  function rel(root, path) {
4239
- const value = relative4(root, path).replace(/\\/g, "/");
4321
+ const value = relative5(root, path).replace(/\\/g, "/");
4240
4322
  return value || ".";
4241
4323
  }
4242
4324
  function hasAnyFile(dir, names) {
@@ -4315,14 +4397,20 @@ function statusFromIssues(issues, essenceVersion) {
4315
4397
  return "healthy";
4316
4398
  }
4317
4399
  function buildDoctorReport(root, args) {
4318
- const projectIdx = args.indexOf("--project");
4319
- 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
+ }
4320
4406
  const workspaceMode = args.includes("--workspace");
4321
4407
  const workspaceInfo = resolveWorkspaceInfo(root, projectArg);
4322
4408
  const workspaceRoot = workspaceInfo.workspaceRoot;
4323
4409
  const appRoot = workspaceMode ? workspaceRoot : workspaceInfo.appRoot;
4410
+ const projectMissing = Boolean(projectArg && !existsSync16(appRoot));
4324
4411
  const projectPath = appRoot === workspaceRoot ? null : rel(workspaceRoot, appRoot);
4325
4412
  const packageManager = detectPackageManager2(workspaceRoot);
4413
+ const cliDependency = localCliDependency(workspaceRoot);
4326
4414
  const detected = detectProject(appRoot);
4327
4415
  const projectJson = readJson2(join18(appRoot, ".decantr", "project.json"));
4328
4416
  const essence = readJson2(join18(appRoot, "decantr.essence.json"));
@@ -4340,6 +4428,7 @@ function buildDoctorReport(root, args) {
4340
4428
  const ciFiles = findCiFiles(workspaceRoot);
4341
4429
  const workflowMode = projectJson?.initialized?.workflowMode ?? null;
4342
4430
  const adoptionMode = projectJson?.initialized?.adoptionMode ?? null;
4431
+ const packHydrationOptional = adoptionMode === "contract-only";
4343
4432
  const missingPackReferences = workspaceMode ? projects.flatMap(
4344
4433
  (project) => collectMissingPackManifestFiles(join18(workspaceRoot, project.path)).map(
4345
4434
  (missing) => `${project.path}/${missing.relativePath}`
@@ -4347,14 +4436,21 @@ function buildDoctorReport(root, args) {
4347
4436
  ) : collectMissingPackManifestFiles(appRoot).map((missing) => missing.relativePath);
4348
4437
  const workspaceProjectsMissingManifest = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
4349
4438
  const projectContextDir = join18(workspaceRoot, projectPath2, ".decantr", "context");
4350
- return !existsSync16(join18(projectContextDir, "pack-manifest.json"));
4439
+ return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "pack-manifest.json"));
4351
4440
  }) : [];
4352
4441
  const workspaceProjectsMissingReviewPack = workspaceMode ? projects.map((project) => project.path).filter((projectPath2) => {
4353
4442
  const projectContextDir = join18(workspaceRoot, projectPath2, ".decantr", "context");
4354
- return !existsSync16(join18(projectContextDir, "review-pack.json"));
4443
+ return !isContractOnlyProject(join18(workspaceRoot, projectPath2)) && !existsSync16(join18(projectContextDir, "review-pack.json"));
4355
4444
  }) : [];
4356
4445
  const issues = [];
4357
- 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) {
4358
4454
  issues.push({
4359
4455
  category: "setup",
4360
4456
  severity: "error",
@@ -4385,6 +4481,14 @@ function buildDoctorReport(root, args) {
4385
4481
  nextCommand: "decantr setup"
4386
4482
  });
4387
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
+ }
4388
4492
  if (essenceVersion === "4.0.0" && !artifactReadmePresent) {
4389
4493
  issues.push({
4390
4494
  category: "generated-artifact",
@@ -4393,7 +4497,7 @@ function buildDoctorReport(root, args) {
4393
4497
  nextCommand: "decantr refresh"
4394
4498
  });
4395
4499
  }
4396
- if (essenceVersion === "4.0.0" && (!existsSync16(contextDir) || !packManifestPresent)) {
4500
+ if (essenceVersion === "4.0.0" && !packHydrationOptional && (!existsSync16(contextDir) || !packManifestPresent)) {
4397
4501
  issues.push({
4398
4502
  category: "generated-artifact",
4399
4503
  severity: "warn",
@@ -4453,7 +4557,7 @@ function buildDoctorReport(root, args) {
4453
4557
  projectPath,
4454
4558
  packageManager,
4455
4559
  cli: {
4456
- localDependency: localCliDependency(workspaceRoot),
4560
+ localDependency: cliDependency,
4457
4561
  runningVersion: readCliPackageVersion()
4458
4562
  },
4459
4563
  project: {
@@ -4564,18 +4668,24 @@ async function cmdDoctor(args = ["doctor"], root = process.cwd()) {
4564
4668
  const report = buildDoctorReport(root, args);
4565
4669
  if (args.includes("--json")) {
4566
4670
  console.log(JSON.stringify(report, null, 2));
4671
+ if (report.issues.some((issue) => issue.severity === "error")) process.exitCode = 1;
4567
4672
  return;
4568
4673
  }
4569
4674
  process.stdout.write(formatDoctorText(report));
4675
+ if (report.issues.some((issue) => issue.severity === "error")) process.exitCode = 1;
4570
4676
  }
4571
4677
 
4572
4678
  // src/commands/export.ts
4573
4679
  import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
4574
- import { dirname as dirname4, join as join19 } from "path";
4680
+ import { dirname as dirname4, isAbsolute, join as join19 } from "path";
4575
4681
  var GREEN5 = "\x1B[32m";
4576
4682
  var RED4 = "\x1B[31m";
4577
4683
  var DIM5 = "\x1B[2m";
4578
4684
  var RESET5 = "\x1B[0m";
4685
+ function resolveOutputPath(projectRoot, output, fallback) {
4686
+ if (!output) return fallback;
4687
+ return isAbsolute(output) ? output : join19(projectRoot, output);
4688
+ }
4579
4689
  var SHADCN_MAP = {
4580
4690
  "--d-bg": "--background",
4581
4691
  "--d-text": "--foreground",
@@ -4724,9 +4834,7 @@ function generateFigmaTokens(tokens) {
4724
4834
  const out = {};
4725
4835
  for (const [key, value] of tokens) {
4726
4836
  const name = key.replace(/^--/, "").replace(/-/g, ".");
4727
- const type = /color|bg|surface|text|border|primary|secondary|accent|error|warning|success|info/.test(
4728
- key
4729
- ) ? "color" : /radius/.test(key) ? "borderRadius" : /shadow/.test(key) ? "shadow" : /gap|space|spacing/.test(key) ? "dimension" : "string";
4837
+ const type = /color|bg|surface|text|border|primary|secondary|accent|error|warning|success|info/.test(key) ? "color" : /radius/.test(key) ? "borderRadius" : /shadow/.test(key) ? "shadow" : /gap|space|spacing/.test(key) ? "dimension" : "string";
4730
4838
  out[name] = {
4731
4839
  $type: type,
4732
4840
  $value: value,
@@ -4760,7 +4868,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4760
4868
  }
4761
4869
  switch (target) {
4762
4870
  case "shadcn": {
4763
- const cssOut = options.output ?? join19(projectRoot, "src", "styles", "shadcn-theme.css");
4871
+ const cssOut = resolveOutputPath(
4872
+ projectRoot,
4873
+ options.output,
4874
+ join19(projectRoot, "src", "styles", "shadcn-theme.css")
4875
+ );
4764
4876
  const jsonOut = join19(projectRoot, "components.json");
4765
4877
  ensureDir(cssOut);
4766
4878
  writeFileSync12(cssOut, generateShadcnCSS(tokens), "utf-8");
@@ -4771,7 +4883,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4771
4883
  break;
4772
4884
  }
4773
4885
  case "tailwind": {
4774
- const out = options.output ?? join19(projectRoot, "tailwind.decantr.config.ts");
4886
+ const out = resolveOutputPath(
4887
+ projectRoot,
4888
+ options.output,
4889
+ join19(projectRoot, "tailwind.decantr.config.ts")
4890
+ );
4775
4891
  ensureDir(out);
4776
4892
  writeFileSync12(out, generateTailwindConfig(tokens), "utf-8");
4777
4893
  console.log(`${GREEN5}Exported Tailwind config:${RESET5}`);
@@ -4779,7 +4895,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4779
4895
  break;
4780
4896
  }
4781
4897
  case "css-vars": {
4782
- const out = options.output ?? join19(projectRoot, "decantr-tokens.css");
4898
+ const out = resolveOutputPath(
4899
+ projectRoot,
4900
+ options.output,
4901
+ join19(projectRoot, "decantr-tokens.css")
4902
+ );
4783
4903
  ensureDir(out);
4784
4904
  writeFileSync12(out, generateCSSVars(tokens), "utf-8");
4785
4905
  console.log(`${GREEN5}Exported CSS variables:${RESET5}`);
@@ -4787,7 +4907,11 @@ async function cmdExport(target, projectRoot, options = {}) {
4787
4907
  break;
4788
4908
  }
4789
4909
  case "figma-tokens": {
4790
- const out = options.output ?? join19(projectRoot, ".decantr", "design", "figma-tokens.json");
4910
+ const out = resolveOutputPath(
4911
+ projectRoot,
4912
+ options.output,
4913
+ join19(projectRoot, ".decantr", "design", "figma-tokens.json")
4914
+ );
4791
4915
  ensureDir(out);
4792
4916
  writeFileSync12(out, generateFigmaTokens(tokens), "utf-8");
4793
4917
  console.log(`${GREEN5}Exported Figma/Tokens Studio tokens:${RESET5}`);
@@ -4810,7 +4934,6 @@ import { join as join20 } from "path";
4810
4934
  var BOLD4 = "\x1B[1m";
4811
4935
  var DIM6 = "\x1B[2m";
4812
4936
  var RESET6 = "\x1B[0m";
4813
- var RED5 = "\x1B[31m";
4814
4937
  var GREEN6 = "\x1B[32m";
4815
4938
  var CYAN3 = "\x1B[36m";
4816
4939
  var YELLOW3 = "\x1B[33m";
@@ -4818,9 +4941,6 @@ var MAGENTA = "\x1B[35m";
4818
4941
  function success(text) {
4819
4942
  return `${GREEN6}${text}${RESET6}`;
4820
4943
  }
4821
- function error(text) {
4822
- return `${RED5}${text}${RESET6}`;
4823
- }
4824
4944
  function dim(text) {
4825
4945
  return `${DIM6}${text}${RESET6}`;
4826
4946
  }
@@ -5036,9 +5156,16 @@ async function cmdMagic(prompt, projectRoot, options) {
5036
5156
  console.log("");
5037
5157
  const essencePath = join20(projectRoot, "decantr.essence.json");
5038
5158
  if (existsSync18(essencePath)) {
5039
- console.log(error(" decantr.essence.json already exists in this directory."));
5040
- console.log(dim(" Remove it first or use a different directory."));
5041
- process.exitCode = 1;
5159
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5160
+ console.log(`${YELLOW3} Decantr is already attached to this project.${RESET6}`);
5161
+ console.log(
5162
+ dim(" decantr magic is greenfield-first; use task-time context for existing apps.")
5163
+ );
5164
+ console.log("");
5165
+ console.log(`${BOLD4}Recommended next steps:${RESET6}`);
5166
+ console.log(` ${cyan(`decantr doctor${projectFlag}`)}`);
5167
+ console.log(` ${cyan(`decantr task <route> "${prompt}"${projectFlag}`)}`);
5168
+ console.log(` ${cyan(`decantr verify --brownfield --local-patterns${projectFlag}`)}`);
5042
5169
  return;
5043
5170
  }
5044
5171
  const detected = detectProject(projectRoot);
@@ -5053,8 +5180,9 @@ async function cmdMagic(prompt, projectRoot, options) {
5053
5180
  dim(" Running brownfield analysis instead so you can attach Decantr deliberately.\n")
5054
5181
  );
5055
5182
  await cmdAnalyze(projectRoot);
5183
+ const projectFlag = options.projectLabel ? ` --project ${options.projectLabel}` : "";
5056
5184
  console.log(
5057
- `${BOLD4}Recommended next step:${RESET6} ${cyan("decantr init --existing --accept-proposal")}`
5185
+ `${BOLD4}Recommended next step:${RESET6} ${cyan(`decantr init${projectFlag} --existing --accept-proposal`)}`
5058
5186
  );
5059
5187
  console.log("");
5060
5188
  return;
@@ -5380,7 +5508,7 @@ import {
5380
5508
  validateLegacyEssenceForMigration
5381
5509
  } from "@decantr/essence-spec";
5382
5510
  var GREEN7 = "\x1B[32m";
5383
- var RED6 = "\x1B[31m";
5511
+ var RED5 = "\x1B[31m";
5384
5512
  var YELLOW4 = "\x1B[33m";
5385
5513
  var RESET7 = "\x1B[0m";
5386
5514
  var DIM7 = "\x1B[2m";
@@ -5448,13 +5576,13 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5448
5576
  const inlineTarget = hasInlineTarget?.split("=")[1];
5449
5577
  const requestedTarget = inlineTarget ?? target;
5450
5578
  if (requestedTarget !== "v4") {
5451
- console.error(`${RED6}Usage: decantr migrate --to v4${RESET7}`);
5579
+ console.error(`${RED5}Usage: decantr migrate --to v4${RESET7}`);
5452
5580
  process.exitCode = 1;
5453
5581
  return;
5454
5582
  }
5455
5583
  const essencePath = join21(projectRoot, "decantr.essence.json");
5456
5584
  if (!existsSync19(essencePath)) {
5457
- console.error(`${RED6}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5585
+ console.error(`${RED5}No decantr.essence.json found. Run \`decantr init\` first.${RESET7}`);
5458
5586
  process.exitCode = 1;
5459
5587
  return;
5460
5588
  }
@@ -5465,7 +5593,7 @@ async function cmdMigrate(projectRoot = process.cwd(), args = []) {
5465
5593
  return;
5466
5594
  }
5467
5595
  if (!result.success) {
5468
- console.error(`${RED6}Migration failed: ${result.error}${RESET7}`);
5596
+ console.error(`${RED5}Migration failed: ${result.error}${RESET7}`);
5469
5597
  process.exitCode = 1;
5470
5598
  return;
5471
5599
  }
@@ -5545,7 +5673,7 @@ function seedOfflineRegistry(projectDir, workspaceRoot) {
5545
5673
  var BOLD5 = "\x1B[1m";
5546
5674
  var DIM8 = "\x1B[2m";
5547
5675
  var RESET8 = "\x1B[0m";
5548
- var RED7 = "\x1B[31m";
5676
+ var RED6 = "\x1B[31m";
5549
5677
  var GREEN8 = "\x1B[32m";
5550
5678
  var CYAN4 = "\x1B[36m";
5551
5679
  var YELLOW5 = "\x1B[33m";
@@ -5557,8 +5685,8 @@ ${BOLD5}${text}${RESET8}
5557
5685
  function success2(text) {
5558
5686
  return `${GREEN8}${text}${RESET8}`;
5559
5687
  }
5560
- function error2(text) {
5561
- return `${RED7}${text}${RESET8}`;
5688
+ function error(text) {
5689
+ return `${RED6}${text}${RESET8}`;
5562
5690
  }
5563
5691
  function dim2(text) {
5564
5692
  return `${DIM8}${text}${RESET8}`;
@@ -5665,13 +5793,13 @@ async function cmdNewProject(projectName, options) {
5665
5793
  const shouldBootstrapRuntime = Boolean(bootstrapAdapter && inferredAdoption === "decantr-css");
5666
5794
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
5667
5795
  console.error(
5668
- error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5796
+ error("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores.")
5669
5797
  );
5670
5798
  process.exitCode = 1;
5671
5799
  return;
5672
5800
  }
5673
5801
  if (existsSync21(projectDir)) {
5674
- console.error(error2(`Directory "${projectName}" already exists.`));
5802
+ console.error(error(`Directory "${projectName}" already exists.`));
5675
5803
  process.exitCode = 1;
5676
5804
  return;
5677
5805
  }
@@ -5679,7 +5807,7 @@ async function cmdNewProject(projectName, options) {
5679
5807
  try {
5680
5808
  initFlags = buildNewProjectInitArgs(options, inferredAdoption);
5681
5809
  } catch (err) {
5682
- console.error(error2(err.message));
5810
+ console.error(error(err.message));
5683
5811
  process.exitCode = 1;
5684
5812
  return;
5685
5813
  }
@@ -5862,11 +5990,11 @@ async function cmdPublish(type, name, projectRoot = process.cwd()) {
5862
5990
  // src/commands/refresh.ts
5863
5991
  import { createHash } from "crypto";
5864
5992
  import { existsSync as existsSync23, readdirSync as readdirSync7, readFileSync as readFileSync17, statSync as statSync6 } from "fs";
5865
- import { join as join25 } from "path";
5993
+ import { isAbsolute as isAbsolute2, join as join25, relative as relative6 } from "path";
5866
5994
  import { collectMissingPackManifestFiles as collectMissingPackManifestFiles2 } from "@decantr/verifier";
5867
5995
  import { isV4 as isV46 } from "@decantr/essence-spec";
5868
5996
  var GREEN9 = "\x1B[32m";
5869
- var RED8 = "\x1B[31m";
5997
+ var RED7 = "\x1B[31m";
5870
5998
  var DIM9 = "\x1B[2m";
5871
5999
  var RESET9 = "\x1B[0m";
5872
6000
  function hashFile(path) {
@@ -5917,18 +6045,29 @@ function newestInputMtime(projectRoot) {
5917
6045
  fileMtimeMs(join25(projectRoot, ".decantr", "project.json"))
5918
6046
  );
5919
6047
  }
6048
+ function isContractOnlyProject2(projectRoot) {
6049
+ const projectJsonPath = join25(projectRoot, ".decantr", "project.json");
6050
+ if (!existsSync23(projectJsonPath)) return false;
6051
+ try {
6052
+ const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
6053
+ return projectJson.initialized?.adoptionMode === "contract-only";
6054
+ } catch {
6055
+ return false;
6056
+ }
6057
+ }
5920
6058
  function checkRefreshFreshness(projectRoot) {
5921
6059
  const contextDir = join25(projectRoot, ".decantr", "context");
5922
6060
  const generated = trackedGeneratedFiles(projectRoot);
5923
6061
  const reasons = [];
6062
+ const packHydrationOptional = isContractOnlyProject2(projectRoot);
5924
6063
  if (!existsSync23(join25(projectRoot, "DECANTR.md"))) reasons.push("DECANTR.md is missing.");
5925
6064
  if (!existsSync23(contextDir)) reasons.push(".decantr/context is missing.");
5926
6065
  if (!existsSync23(join25(contextDir, "scaffold.md"))) {
5927
6066
  reasons.push(".decantr/context/scaffold.md is missing.");
5928
6067
  }
5929
- if (!existsSync23(join25(contextDir, "pack-manifest.json"))) {
6068
+ if (!packHydrationOptional && !existsSync23(join25(contextDir, "pack-manifest.json"))) {
5930
6069
  reasons.push(".decantr/context/pack-manifest.json is missing.");
5931
- } else {
6070
+ } else if (existsSync23(join25(contextDir, "pack-manifest.json"))) {
5932
6071
  const missingPackFiles = collectMissingPackManifestFiles2(projectRoot);
5933
6072
  if (missingPackFiles.length > 0) {
5934
6073
  reasons.push(
@@ -5979,10 +6118,19 @@ function summarizeChanges(projectRoot, before, after) {
5979
6118
  unchanged: unchanged.sort()
5980
6119
  };
5981
6120
  }
5982
- function printRefreshSummary(summary) {
6121
+ function displayGeneratedPath(summary, file, displayRoot) {
6122
+ if (!displayRoot) return file;
6123
+ const absolutePath = join25(summary.projectRoot, file);
6124
+ const relativePath = relative6(displayRoot, absolutePath).replace(/\\/g, "/");
6125
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute2(relativePath)) {
6126
+ return relativePath;
6127
+ }
6128
+ return absolutePath;
6129
+ }
6130
+ function printRefreshSummary(summary, displayRoot) {
5983
6131
  if (summary.check) {
5984
6132
  if (summary.stale) {
5985
- console.log(`${RED8}Generated Decantr context is stale.${RESET9}`);
6133
+ console.log(`${RED7}Generated Decantr context is stale.${RESET9}`);
5986
6134
  for (const reason of summary.reasons) console.log(` ${reason}`);
5987
6135
  console.log(`${DIM9}Run \`decantr refresh\` to regenerate derived files.${RESET9}`);
5988
6136
  } else {
@@ -5998,7 +6146,9 @@ function printRefreshSummary(summary) {
5998
6146
  for (const [label, files] of groups) {
5999
6147
  if (files.length === 0) continue;
6000
6148
  console.log(`${GREEN9}${label}:${RESET9}`);
6001
- for (const file of files) console.log(` ${DIM9}${file}${RESET9}`);
6149
+ for (const file of files) {
6150
+ console.log(` ${DIM9}${displayGeneratedPath(summary, file, displayRoot)}${RESET9}`);
6151
+ }
6002
6152
  }
6003
6153
  if (groups.every(([, files]) => files.length === 0)) {
6004
6154
  console.log(`${GREEN9}Generated files were already current.${RESET9}`);
@@ -6007,7 +6157,7 @@ function printRefreshSummary(summary) {
6007
6157
  async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6008
6158
  const essencePath = join25(projectRoot, "decantr.essence.json");
6009
6159
  if (!existsSync23(essencePath)) {
6010
- console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6160
+ console.error(`${RED7}No decantr.essence.json found. Run \`decantr init\` first.${RESET9}`);
6011
6161
  process.exitCode = 1;
6012
6162
  return;
6013
6163
  }
@@ -6017,14 +6167,14 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6017
6167
  const parsed = JSON.parse(raw);
6018
6168
  if (!isV46(parsed)) {
6019
6169
  console.error(
6020
- `${RED8}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6170
+ `${RED7}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET9}`
6021
6171
  );
6022
6172
  process.exitCode = 1;
6023
6173
  return;
6024
6174
  }
6025
6175
  essence = parsed;
6026
6176
  } catch (e) {
6027
- console.error(`${RED8}Could not read essence: ${e.message}${RESET9}`);
6177
+ console.error(`${RED7}Could not read essence: ${e.message}${RESET9}`);
6028
6178
  process.exitCode = 1;
6029
6179
  return;
6030
6180
  }
@@ -6033,7 +6183,7 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6033
6183
  if (options.json) {
6034
6184
  console.log(JSON.stringify(summary2, null, 2));
6035
6185
  } else {
6036
- printRefreshSummary(summary2);
6186
+ printRefreshSummary(summary2, options.displayRoot);
6037
6187
  }
6038
6188
  if (summary2.stale) process.exitCode = 1;
6039
6189
  return;
@@ -6050,17 +6200,19 @@ async function cmdRefresh(projectRoot = process.cwd(), options = {}) {
6050
6200
  if (options.json) {
6051
6201
  console.log(JSON.stringify({ ...summary, result }, null, 2));
6052
6202
  } else if (options.listChanges) {
6053
- printRefreshSummary(summary);
6203
+ printRefreshSummary(summary, options.displayRoot);
6054
6204
  } else {
6055
6205
  console.log(`${GREEN9}Regenerated:${RESET9}`);
6056
- console.log(` ${DIM9}DECANTR.md${RESET9}`);
6206
+ console.log(
6207
+ ` ${DIM9}${displayGeneratedPath(summary, "DECANTR.md", options.displayRoot)}${RESET9}`
6208
+ );
6057
6209
  for (const css of result.cssFiles) {
6058
6210
  const rel2 = css.replace(projectRoot + "/", "");
6059
- console.log(` ${DIM9}${rel2}${RESET9}`);
6211
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6060
6212
  }
6061
6213
  for (const ctx of result.contextFiles) {
6062
6214
  const rel2 = ctx.replace(projectRoot + "/", "");
6063
- console.log(` ${DIM9}${rel2}${RESET9}`);
6215
+ console.log(` ${DIM9}${displayGeneratedPath(summary, rel2, options.displayRoot)}${RESET9}`);
6064
6216
  }
6065
6217
  }
6066
6218
  console.log("");
@@ -6072,7 +6224,7 @@ import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync14 } from "fs";
6072
6224
  import { join as join26 } from "path";
6073
6225
  import { API_CONTENT_TYPES, RegistryAPIClient as RegistryAPIClient2 } from "@decantr/registry";
6074
6226
  var GREEN10 = "\x1B[32m";
6075
- var RED9 = "\x1B[31m";
6227
+ var RED8 = "\x1B[31m";
6076
6228
  var DIM10 = "\x1B[2m";
6077
6229
  var CYAN5 = "\x1B[36m";
6078
6230
  var YELLOW6 = "\x1B[33m";
@@ -6086,13 +6238,13 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
6086
6238
  });
6087
6239
  const healthy = await apiClient.checkHealth();
6088
6240
  if (!healthy) {
6089
- console.error(`${RED9}Registry API is unavailable. Check your connection.${RESET10}`);
6241
+ console.error(`${RED8}Registry API is unavailable. Check your connection.${RESET10}`);
6090
6242
  process.exitCode = 1;
6091
6243
  return;
6092
6244
  }
6093
6245
  const types = options.type ? [options.type] : ALL_CONTENT_TYPES;
6094
6246
  if (options.type && !ALL_CONTENT_TYPES.includes(options.type)) {
6095
- console.error(`${RED9}Unknown content type: ${options.type}${RESET10}`);
6247
+ console.error(`${RED8}Unknown content type: ${options.type}${RESET10}`);
6096
6248
  console.error(`${DIM10}Valid types: ${ALL_CONTENT_TYPES.join(", ")}${RESET10}`);
6097
6249
  process.exitCode = 1;
6098
6250
  return;
@@ -6127,7 +6279,7 @@ Mirroring registry content to ${DIM10}.decantr/cache/${RESET10}
6127
6279
  console.log(` ${GREEN10}\u2713${RESET10} ${type}: ${CYAN5}${itemCount}${RESET10} items`);
6128
6280
  } catch (e) {
6129
6281
  failed.push(type);
6130
- console.log(` ${RED9}\u2717${RESET10} ${type}: ${e.message}`);
6282
+ console.log(` ${RED8}\u2717${RESET10} ${type}: ${e.message}`);
6131
6283
  }
6132
6284
  }
6133
6285
  const manifest = {
@@ -6156,13 +6308,13 @@ import { existsSync as existsSync25, readFileSync as readFileSync18, rmSync as r
6156
6308
  import { join as join27 } from "path";
6157
6309
  import { isV4 as isV47 } from "@decantr/essence-spec";
6158
6310
  var GREEN11 = "\x1B[32m";
6159
- var RED10 = "\x1B[31m";
6311
+ var RED9 = "\x1B[31m";
6160
6312
  var DIM11 = "\x1B[2m";
6161
6313
  var RESET11 = "\x1B[0m";
6162
6314
  function readV4Essence2(projectRoot) {
6163
6315
  const essencePath = join27(projectRoot, "decantr.essence.json");
6164
6316
  if (!existsSync25(essencePath)) {
6165
- console.error(`${RED10}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6317
+ console.error(`${RED9}No decantr.essence.json found. Run \`decantr init\` first.${RESET11}`);
6166
6318
  process.exitCode = 1;
6167
6319
  return null;
6168
6320
  }
@@ -6170,13 +6322,13 @@ function readV4Essence2(projectRoot) {
6170
6322
  try {
6171
6323
  parsed = JSON.parse(readFileSync18(essencePath, "utf-8"));
6172
6324
  } catch (e) {
6173
- console.error(`${RED10}Could not read essence: ${e.message}${RESET11}`);
6325
+ console.error(`${RED9}Could not read essence: ${e.message}${RESET11}`);
6174
6326
  process.exitCode = 1;
6175
6327
  return null;
6176
6328
  }
6177
6329
  if (!isV47(parsed)) {
6178
6330
  console.error(
6179
- `${RED10}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6331
+ `${RED9}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET11}`
6180
6332
  );
6181
6333
  process.exitCode = 1;
6182
6334
  return null;
@@ -6186,6 +6338,15 @@ function readV4Essence2(projectRoot) {
6186
6338
  function writeEssence2(essencePath, essence) {
6187
6339
  writeFileSync15(essencePath, JSON.stringify(essence, null, 2) + "\n");
6188
6340
  }
6341
+ function readFlagValue2(args, name) {
6342
+ const prefix = `--${name}=`;
6343
+ for (let index = 0; index < args.length; index += 1) {
6344
+ const arg = args[index];
6345
+ if (arg === `--${name}` && args[index + 1]) return args[index + 1];
6346
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
6347
+ }
6348
+ return void 0;
6349
+ }
6189
6350
  function recomputeGlobalFeatures(essence) {
6190
6351
  const all = /* @__PURE__ */ new Set();
6191
6352
  for (const section of essence.blueprint.sections || []) {
@@ -6208,7 +6369,7 @@ function removeRoutes(essence, sectionId, pageId) {
6208
6369
  }
6209
6370
  async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6210
6371
  if (!sectionId) {
6211
- console.error(`${RED10}Usage: decantr remove section <sectionId>${RESET11}`);
6372
+ console.error(`${RED9}Usage: decantr remove section <sectionId>${RESET11}`);
6212
6373
  process.exitCode = 1;
6213
6374
  return;
6214
6375
  }
@@ -6218,7 +6379,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6218
6379
  const sections = essence.blueprint.sections;
6219
6380
  const idx = sections.findIndex((s) => s.id === sectionId);
6220
6381
  if (idx === -1) {
6221
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6382
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6222
6383
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6223
6384
  process.exitCode = 1;
6224
6385
  return;
@@ -6240,7 +6401,7 @@ async function cmdRemoveSection(sectionId, args, projectRoot = process.cwd()) {
6240
6401
  }
6241
6402
  async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6242
6403
  if (!path || !path.includes("/")) {
6243
- console.error(`${RED10}Usage: decantr remove page <section>/<page>${RESET11}`);
6404
+ console.error(`${RED9}Usage: decantr remove page <section>/<page>${RESET11}`);
6244
6405
  console.error(`${DIM11}Example: decantr remove page settings/notifications${RESET11}`);
6245
6406
  process.exitCode = 1;
6246
6407
  return;
@@ -6252,14 +6413,14 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6252
6413
  const sections = essence.blueprint.sections;
6253
6414
  const section = sections.find((s) => s.id === sectionId);
6254
6415
  if (!section) {
6255
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6416
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6256
6417
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6257
6418
  process.exitCode = 1;
6258
6419
  return;
6259
6420
  }
6260
6421
  const pageIdx = section.pages.findIndex((p) => p.id === pageId);
6261
6422
  if (pageIdx === -1) {
6262
- console.error(`${RED10}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6423
+ console.error(`${RED9}Page "${pageId}" not found in section "${sectionId}".${RESET11}`);
6263
6424
  console.error(`${DIM11}Available pages: ${section.pages.map((p) => p.id).join(", ")}${RESET11}`);
6264
6425
  process.exitCode = 1;
6265
6426
  return;
@@ -6276,7 +6437,7 @@ async function cmdRemovePage(path, args, projectRoot = process.cwd()) {
6276
6437
  }
6277
6438
  async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6278
6439
  if (!feature) {
6279
- console.error(`${RED10}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6440
+ console.error(`${RED9}Usage: decantr remove feature <feature> [--section <sectionId>]${RESET11}`);
6280
6441
  process.exitCode = 1;
6281
6442
  return;
6282
6443
  }
@@ -6284,15 +6445,12 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6284
6445
  if (!loaded) return;
6285
6446
  const { essence, essencePath } = loaded;
6286
6447
  let sectionId;
6287
- const sectionIdx = args.indexOf("--section");
6288
- if (sectionIdx !== -1 && args[sectionIdx + 1]) {
6289
- sectionId = args[sectionIdx + 1];
6290
- }
6448
+ sectionId = readFlagValue2(args, "section");
6291
6449
  if (sectionId) {
6292
6450
  const sections = essence.blueprint.sections;
6293
6451
  const section = sections.find((s) => s.id === sectionId);
6294
6452
  if (!section) {
6295
- console.error(`${RED10}Section "${sectionId}" not found.${RESET11}`);
6453
+ console.error(`${RED9}Section "${sectionId}" not found.${RESET11}`);
6296
6454
  console.error(`${DIM11}Available sections: ${sections.map((s) => s.id).join(", ")}${RESET11}`);
6297
6455
  process.exitCode = 1;
6298
6456
  return;
@@ -6320,7 +6478,7 @@ async function cmdRemoveFeature(feature, args, projectRoot = process.cwd()) {
6320
6478
  import { existsSync as existsSync26, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
6321
6479
  import { join as join28 } from "path";
6322
6480
  var GREEN12 = "\x1B[32m";
6323
- var RED11 = "\x1B[31m";
6481
+ var RED10 = "\x1B[31m";
6324
6482
  var YELLOW7 = "\x1B[33m";
6325
6483
  var RESET12 = "\x1B[0m";
6326
6484
  var DIM12 = "\x1B[2m";
@@ -6339,12 +6497,12 @@ async function cmdSyncDrift(projectRoot = process.cwd()) {
6339
6497
  try {
6340
6498
  entries = JSON.parse(readFileSync19(driftLogPath, "utf-8"));
6341
6499
  } catch {
6342
- console.error(`${RED11}Could not parse drift-log.json${RESET12}`);
6500
+ console.error(`${RED10}Could not parse drift-log.json${RESET12}`);
6343
6501
  process.exitCode = 1;
6344
6502
  return;
6345
6503
  }
6346
6504
  if (!Array.isArray(entries)) {
6347
- console.error(`${RED11}drift-log.json is not an array${RESET12}`);
6505
+ console.error(`${RED10}drift-log.json is not an array${RESET12}`);
6348
6506
  process.exitCode = 1;
6349
6507
  return;
6350
6508
  }
@@ -6362,7 +6520,7 @@ ${BOLD6}Unresolved Drift Entries (${unresolved.length})${RESET12}
6362
6520
  `);
6363
6521
  for (let i = 0; i < unresolved.length; i++) {
6364
6522
  const entry = unresolved[i];
6365
- const severityColor = entry.severity === "error" ? RED11 : YELLOW7;
6523
+ const severityColor = entry.severity === "error" ? RED10 : YELLOW7;
6366
6524
  const icon = entry.severity === "error" ? "x" : "!";
6367
6525
  console.log(
6368
6526
  ` ${severityColor}${icon}${RESET12} ${BOLD6}#${i + 1}${RESET12} [${entry.rule}] ${entry.message}`
@@ -6645,7 +6803,7 @@ import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSy
6645
6803
  import { join as join29 } from "path";
6646
6804
  import { isV4 as isV48 } from "@decantr/essence-spec";
6647
6805
  var GREEN14 = "\x1B[32m";
6648
- var RED12 = "\x1B[31m";
6806
+ var RED11 = "\x1B[31m";
6649
6807
  var YELLOW8 = "\x1B[33m";
6650
6808
  var DIM14 = "\x1B[2m";
6651
6809
  var RESET14 = "\x1B[0m";
@@ -6654,14 +6812,14 @@ var VALID_THEME_MODES = ["light", "dark", "auto"];
6654
6812
  async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6655
6813
  if (!themeName) {
6656
6814
  console.error(
6657
- `${RED12}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6815
+ `${RED11}Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]${RESET14}`
6658
6816
  );
6659
6817
  process.exitCode = 1;
6660
6818
  return;
6661
6819
  }
6662
6820
  const essencePath = join29(projectRoot, "decantr.essence.json");
6663
6821
  if (!existsSync27(essencePath)) {
6664
- console.error(`${RED12}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6822
+ console.error(`${RED11}No decantr.essence.json found. Run \`decantr init\` first.${RESET14}`);
6665
6823
  process.exitCode = 1;
6666
6824
  return;
6667
6825
  }
@@ -6669,13 +6827,13 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6669
6827
  try {
6670
6828
  parsed = JSON.parse(readFileSync20(essencePath, "utf-8"));
6671
6829
  } catch (e) {
6672
- console.error(`${RED12}Could not read essence: ${e.message}${RESET14}`);
6830
+ console.error(`${RED11}Could not read essence: ${e.message}${RESET14}`);
6673
6831
  process.exitCode = 1;
6674
6832
  return;
6675
6833
  }
6676
6834
  if (!isV48(parsed)) {
6677
6835
  console.error(
6678
- `${RED12}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6836
+ `${RED11}Active workflows require Essence v4.0.0. Run \`decantr migrate --to v4\` first.${RESET14}`
6679
6837
  );
6680
6838
  process.exitCode = 1;
6681
6839
  return;
@@ -6697,14 +6855,14 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
6697
6855
  }
6698
6856
  if (shape && !VALID_THEME_SHAPES.includes(shape)) {
6699
6857
  console.error(
6700
- `${RED12}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6858
+ `${RED11}Invalid shape "${shape}". Must be one of: ${VALID_THEME_SHAPES.join(", ")}.${RESET14}`
6701
6859
  );
6702
6860
  process.exitCode = 1;
6703
6861
  return;
6704
6862
  }
6705
6863
  if (mode && !VALID_THEME_MODES.includes(mode)) {
6706
6864
  console.error(
6707
- `${RED12}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6865
+ `${RED11}Invalid mode "${mode}". Must be one of: ${VALID_THEME_MODES.join(", ")}.${RESET14}`
6708
6866
  );
6709
6867
  process.exitCode = 1;
6710
6868
  return;
@@ -7208,7 +7366,7 @@ function importTheme(projectRoot, sourcePath) {
7208
7366
  var BOLD9 = "\x1B[1m";
7209
7367
  var DIM16 = "\x1B[2m";
7210
7368
  var RESET16 = "\x1B[0m";
7211
- var RED13 = "\x1B[31m";
7369
+ var RED12 = "\x1B[31m";
7212
7370
  var GREEN16 = "\x1B[32m";
7213
7371
  var CYAN9 = "\x1B[36m";
7214
7372
  var YELLOW10 = "\x1B[33m";
@@ -7220,8 +7378,8 @@ ${BOLD9}${text}${RESET16}
7220
7378
  function success3(text) {
7221
7379
  return `${GREEN16}${text}${RESET16}`;
7222
7380
  }
7223
- function error3(text) {
7224
- return `${RED13}${text}${RESET16}`;
7381
+ function error2(text) {
7382
+ return `${RED12}${text}${RESET16}`;
7225
7383
  }
7226
7384
  function dim3(text) {
7227
7385
  return `${DIM16}${text}${RESET16}`;
@@ -7731,7 +7889,7 @@ function getPublicAPIClient() {
7731
7889
  });
7732
7890
  }
7733
7891
  function resolveUserPath(inputPath, cwd = process.cwd()) {
7734
- return isAbsolute(inputPath) ? inputPath : resolve4(cwd, inputPath);
7892
+ return isAbsolute3(inputPath) ? inputPath : resolve4(cwd, inputPath);
7735
7893
  }
7736
7894
  function extractHostedAssetPaths(indexHtml) {
7737
7895
  const assetPaths = /* @__PURE__ */ new Set();
@@ -7944,18 +8102,13 @@ async function printRegistryIntelligenceSummary(namespace, jsonOutput = false) {
7944
8102
  }
7945
8103
  }
7946
8104
  async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput = false, writeContext = false) {
7947
- const client = getPublicAPIClient();
7948
- const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
7949
- if (!existsSync29(resolvedPath)) {
7950
- throw new Error(`Essence file not found at ${resolvedPath}`);
7951
- }
7952
- const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
7953
- const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
7954
- const contextDir = join31(dirname5(resolvedPath), ".decantr", "context");
8105
+ const { resolvedPath, bundle, contextDir } = await compileHostedExecutionPackBundle(
8106
+ essencePath,
8107
+ namespace
8108
+ );
7955
8109
  let writtenContextPaths = [];
7956
8110
  if (writeContext) {
7957
- mkdirSync16(contextDir, { recursive: true });
7958
- const written = writeExecutionPackBundleArtifacts(
8111
+ const written = writeHostedExecutionPackContextArtifacts(
7959
8112
  contextDir,
7960
8113
  bundle
7961
8114
  );
@@ -7990,6 +8143,21 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
7990
8143
  console.log(` ${cyan3(route.path)} -> ${pageLabel} [${patterns}]`);
7991
8144
  }
7992
8145
  }
8146
+ async function compileHostedExecutionPackBundle(essencePath, namespace) {
8147
+ const client = getPublicAPIClient();
8148
+ const resolvedPath = essencePath ? resolveUserPath(essencePath) : join31(process.cwd(), "decantr.essence.json");
8149
+ if (!existsSync29(resolvedPath)) {
8150
+ throw new Error(`Essence file not found at ${resolvedPath}`);
8151
+ }
8152
+ const essence = JSON.parse(readFileSync22(resolvedPath, "utf-8"));
8153
+ const bundle = await client.compileExecutionPacks(essence, namespace ? { namespace } : void 0);
8154
+ const contextDir = join31(dirname5(resolvedPath), ".decantr", "context");
8155
+ return { resolvedPath, bundle, contextDir };
8156
+ }
8157
+ function writeHostedExecutionPackContextArtifacts(contextDir, bundle) {
8158
+ mkdirSync16(contextDir, { recursive: true });
8159
+ return writeExecutionPackBundleArtifacts(contextDir, bundle);
8160
+ }
7993
8161
  function resolvePagePackIdForRoute(essencePath, route) {
7994
8162
  if (!existsSync29(essencePath)) {
7995
8163
  throw new Error(`Essence file not found at ${essencePath}`);
@@ -8315,22 +8483,22 @@ function patternCandidateFromRegistryItem(item, source) {
8315
8483
  { source, slug }
8316
8484
  );
8317
8485
  }
8318
- function readSuggestCodeContext(route, file) {
8486
+ function readSuggestCodeContext(projectRoot, route, file) {
8319
8487
  const pieces = [];
8320
8488
  if (file) {
8321
- const resolved = isAbsolute(file) ? file : join31(process.cwd(), file);
8489
+ const resolved = isAbsolute3(file) ? file : join31(projectRoot, file);
8322
8490
  if (existsSync29(resolved)) {
8323
8491
  pieces.push(readFileSync22(resolved, "utf-8"));
8324
8492
  }
8325
8493
  }
8326
8494
  if (route) {
8327
- const analysisPath = join31(process.cwd(), ".decantr", "analysis.json");
8495
+ const analysisPath = join31(projectRoot, ".decantr", "analysis.json");
8328
8496
  if (existsSync29(analysisPath)) {
8329
8497
  try {
8330
8498
  const analysis = JSON.parse(readFileSync22(analysisPath, "utf-8"));
8331
8499
  const routeEntry = analysis.routes?.routes?.find((entry) => entry.path === route);
8332
8500
  if (routeEntry?.file) {
8333
- const resolved = join31(process.cwd(), routeEntry.file);
8501
+ const resolved = join31(projectRoot, routeEntry.file);
8334
8502
  if (existsSync29(resolved)) {
8335
8503
  pieces.push(readFileSync22(resolved, "utf-8"));
8336
8504
  }
@@ -8341,6 +8509,28 @@ function readSuggestCodeContext(route, file) {
8341
8509
  }
8342
8510
  return pieces.join("\n\n").slice(0, 2e4);
8343
8511
  }
8512
+ function localPatternMatches(projectRoot, query) {
8513
+ if (!projectRoot) return [];
8514
+ const pack = readLocalPatternPack(projectRoot);
8515
+ const patterns = Array.isArray(pack?.patterns) ? pack.patterns : [];
8516
+ const queryTerms = query.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1);
8517
+ if (queryTerms.length === 0) return [];
8518
+ return patterns.map((pattern) => {
8519
+ const id = typeof pattern.id === "string" ? pattern.id : "local-pattern";
8520
+ const label = typeof pattern.label === "string" ? pattern.label : null;
8521
+ const role = typeof pattern.role === "string" ? pattern.role : null;
8522
+ const haystack = [
8523
+ id,
8524
+ label,
8525
+ role,
8526
+ typeof pattern.decide === "string" ? pattern.decide : null,
8527
+ ...Array.isArray(pattern.appliesTo) ? pattern.appliesTo : [],
8528
+ ...Array.isArray(pattern.componentPaths) ? pattern.componentPaths : []
8529
+ ].filter((entry) => typeof entry === "string").join(" ").toLowerCase();
8530
+ const score = queryTerms.reduce((sum, term) => sum + (haystack.includes(term) ? 1 : 0), 0);
8531
+ return { id, label, role, score };
8532
+ }).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, 5);
8533
+ }
8344
8534
  async function loadPatternDiscoveryCandidates(registryClient) {
8345
8535
  const candidates = [];
8346
8536
  const seen = /* @__PURE__ */ new Set();
@@ -8389,9 +8579,9 @@ async function cmdSuggest(query, options = {}) {
8389
8579
  }
8390
8580
  }
8391
8581
  const registryClient = new RegistryClient({
8392
- cacheDir: join31(process.cwd(), ".decantr", "cache")
8582
+ cacheDir: join31(options.projectRoot ?? process.cwd(), ".decantr", "cache")
8393
8583
  });
8394
- const code = options.fromCode || options.file ? readSuggestCodeContext(options.route, options.file) : "";
8584
+ const code = options.fromCode || options.file ? readSuggestCodeContext(options.projectRoot ?? process.cwd(), options.route, options.file) : "";
8395
8585
  const candidates = await loadPatternDiscoveryCandidates(registryClient);
8396
8586
  const matches = rankPatternCandidates(
8397
8587
  {
@@ -8422,6 +8612,16 @@ async function cmdSuggest(query, options = {}) {
8422
8612
  `Pattern suggestions for "${query}"${contextBits.length > 0 ? ` (${contextBits.join(", ")})` : ""}`
8423
8613
  )
8424
8614
  );
8615
+ const localMatches = localPatternMatches(options.projectRoot, query);
8616
+ if (localMatches.length > 0) {
8617
+ console.log(`${BOLD9}Project-owned local law:${RESET16}`);
8618
+ for (const match of localMatches) {
8619
+ const details = [match.label, match.role].filter(Boolean).join(" | ");
8620
+ console.log(` ${cyan3(match.id)}${details ? ` ${dim3(details)}` : ""}`);
8621
+ }
8622
+ console.log("");
8623
+ console.log(`${BOLD9}Registry patterns:${RESET16}`);
8624
+ }
8425
8625
  for (const match of matches.slice(0, 8)) {
8426
8626
  const candidate = match.candidate;
8427
8627
  const slug = candidate.slug || candidate.id;
@@ -8445,7 +8645,7 @@ async function cmdSuggest(query, options = {}) {
8445
8645
  }
8446
8646
  async function cmdGet(type, id) {
8447
8647
  if (!isGetContentType(type)) {
8448
- console.error(error3(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8648
+ console.error(error2(`Invalid type "${type}". Must be one of: ${GET_CONTENT_TYPES.join(", ")}`));
8449
8649
  process.exitCode = 1;
8450
8650
  return;
8451
8651
  }
@@ -8463,7 +8663,7 @@ async function cmdGet(type, id) {
8463
8663
  console.log(JSON.stringify(bundled.data, null, 2));
8464
8664
  return;
8465
8665
  }
8466
- console.error(error3(`${type} "${id}" not found.`));
8666
+ console.error(error2(`${type} "${id}" not found.`));
8467
8667
  process.exitCode = 1;
8468
8668
  return;
8469
8669
  }
@@ -8473,7 +8673,7 @@ async function cmdValidate(path) {
8473
8673
  try {
8474
8674
  raw = readFileSync22(essencePath, "utf-8");
8475
8675
  } catch {
8476
- console.error(error3(`Could not read ${essencePath}`));
8676
+ console.error(error2(`Could not read ${essencePath}`));
8477
8677
  process.exitCode = 1;
8478
8678
  return;
8479
8679
  }
@@ -8481,7 +8681,7 @@ async function cmdValidate(path) {
8481
8681
  try {
8482
8682
  essence = JSON.parse(raw);
8483
8683
  } catch (e) {
8484
- console.error(error3(`Invalid JSON: ${e.message}`));
8684
+ console.error(error2(`Invalid JSON: ${e.message}`));
8485
8685
  process.exitCode = 1;
8486
8686
  return;
8487
8687
  }
@@ -8491,9 +8691,9 @@ async function cmdValidate(path) {
8491
8691
  if (result.valid) {
8492
8692
  console.log(success3(`Essence is valid (${detectedVersion}).`));
8493
8693
  } else {
8494
- console.error(error3("Validation failed:"));
8694
+ console.error(error2("Validation failed:"));
8495
8695
  for (const err of result.errors) {
8496
- console.error(` ${RED13}${err}${RESET16}`);
8696
+ console.error(` ${RED12}${err}${RESET16}`);
8497
8697
  }
8498
8698
  process.exitCode = 1;
8499
8699
  return;
@@ -8532,7 +8732,7 @@ async function cmdValidate(path) {
8532
8732
  async function cmdList(type, sort, recommended, intelligenceSource, blueprintSet) {
8533
8733
  if (!isApiContentType(type)) {
8534
8734
  console.error(
8535
- error3(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8735
+ error2(`Invalid type "${type}". Must be one of: ${LIST_CONTENT_TYPES.join(", ")}`)
8536
8736
  );
8537
8737
  process.exitCode = 1;
8538
8738
  return;
@@ -8694,7 +8894,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8694
8894
  const proposal = readBrownfieldProposal(input.projectRoot);
8695
8895
  if (!proposal) {
8696
8896
  console.log(
8697
- error3(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8897
+ error2(`No observed brownfield proposal found at ${proposalPath(input.projectRoot)}.`)
8698
8898
  );
8699
8899
  console.log(
8700
8900
  dim3(
@@ -8709,7 +8909,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8709
8909
  let essence;
8710
8910
  let backupPath = null;
8711
8911
  if (input.mode === "accept" && hasEssence) {
8712
- console.log(error3("Refusing to accept proposal over an existing decantr.essence.json."));
8912
+ console.log(error2("Refusing to accept proposal over an existing decantr.essence.json."));
8713
8913
  console.log(
8714
8914
  dim3(
8715
8915
  "Use `--merge-proposal` to preserve the existing contract or `--replace-essence` for an explicit destructive replacement."
@@ -8722,7 +8922,7 @@ async function applyAcceptedBrownfieldProposal(input) {
8722
8922
  const existing = JSON.parse(readFileSync22(essencePath, "utf-8"));
8723
8923
  if (!isV49(existing)) {
8724
8924
  console.log(
8725
- error3(
8925
+ error2(
8726
8926
  "Existing essence is not v4. Run `decantr migrate --to v4` before merging a brownfield proposal."
8727
8927
  )
8728
8928
  );
@@ -8736,10 +8936,10 @@ async function applyAcceptedBrownfieldProposal(input) {
8736
8936
  const validation = validateEssence2(essence);
8737
8937
  if (!validation.valid) {
8738
8938
  console.log(
8739
- error3("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8939
+ error2("Brownfield proposal produced an invalid Decantr essence. No files were changed.")
8740
8940
  );
8741
8941
  for (const validationError of validation.errors) {
8742
- console.log(` ${RED13}${validationError}${RESET16}`);
8942
+ console.log(` ${RED12}${validationError}${RESET16}`);
8743
8943
  }
8744
8944
  process.exitCode = 1;
8745
8945
  return;
@@ -8785,13 +8985,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8785
8985
  }
8786
8986
  const appliedRuleFiles = input.assistantBridge === "apply" ? applyAssistantBridge(input.projectRoot, input.detected) : [];
8787
8987
  console.log(success3("\nBrownfield proposal accepted.\n"));
8988
+ const projectLabel = input.workspaceInfo.appRoot !== input.workspaceInfo.workspaceRoot ? relative7(input.workspaceInfo.workspaceRoot, input.workspaceInfo.appRoot).replace(/\\/g, "/") : void 0;
8788
8989
  console.log(" Files created/updated:");
8789
- console.log(` ${cyan3("decantr.essence.json")} Observed brownfield contract`);
8790
- console.log(` ${cyan3("DECANTR.md")} Reconciled assistant guidance`);
8791
- console.log(` ${cyan3(".decantr/project.json")} Brownfield attach metadata`);
8792
- console.log(` ${cyan3(".decantr/context/")} Generated contract context`);
8990
+ console.log(
8991
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "decantr.essence.json"))} Observed brownfield contract`
8992
+ );
8993
+ console.log(
8994
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, "DECANTR.md"))} Reconciled assistant guidance`
8995
+ );
8996
+ console.log(
8997
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/project.json"))} Brownfield attach metadata`
8998
+ );
8999
+ console.log(
9000
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/"))} Generated contract context`
9001
+ );
8793
9002
  if (assistantBridgePath) {
8794
- console.log(` ${cyan3(".decantr/context/assistant-bridge.md")} Assistant bridge preview`);
9003
+ console.log(
9004
+ ` ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/context/assistant-bridge.md"))} Assistant bridge preview`
9005
+ );
8795
9006
  }
8796
9007
  if (appliedRuleFiles.length > 0) {
8797
9008
  console.log(` ${dim3(`Rule bridge applied: ${appliedRuleFiles.join(", ")}`)}`);
@@ -8802,16 +9013,24 @@ async function applyAcceptedBrownfieldProposal(input) {
8802
9013
  console.log("");
8803
9014
  console.log(" Generated context:");
8804
9015
  for (const contextFile of refreshResult.contextFiles.slice(0, 8)) {
8805
- console.log(` ${dim3(contextFile.replace(`${input.projectRoot}/`, ""))}`);
9016
+ console.log(
9017
+ ` ${dim3(displayProjectPath(input.workspaceInfo, contextFile.replace(`${input.projectRoot}/`, "")))}`
9018
+ );
8806
9019
  }
8807
9020
  if (refreshResult.contextFiles.length > 8) {
8808
9021
  console.log(` ${dim3(`(+${refreshResult.contextFiles.length - 8} more)`)}`);
8809
9022
  }
8810
9023
  console.log("");
8811
9024
  console.log(" Next steps:");
8812
- console.log(` 1. Run ${cyan3("decantr check --brownfield")} to verify contract coverage`);
8813
- console.log(` 2. Read ${cyan3(".decantr/brownfield-report.md")} for unresolved doctrine risks`);
8814
- console.log(` 3. Use ${cyan3("decantr rules preview")} before mutating assistant rule files`);
9025
+ console.log(
9026
+ ` 1. Run ${cyan3(withProject("decantr check --brownfield", projectLabel))} to verify contract coverage`
9027
+ );
9028
+ console.log(
9029
+ ` 2. Read ${cyan3(displayProjectPath(input.workspaceInfo, ".decantr/brownfield-report.md"))} for unresolved doctrine risks`
9030
+ );
9031
+ console.log(
9032
+ ` 3. Use ${cyan3(withProject("decantr rules preview", projectLabel))} before mutating assistant rule files`
9033
+ );
8815
9034
  console.log("");
8816
9035
  }
8817
9036
  async function cmdInit(args) {
@@ -8868,7 +9087,7 @@ async function cmdInit(args) {
8868
9087
  }
8869
9088
  if (policy.workflowMode === "brownfield-attach" && detected.existingEssence) {
8870
9089
  console.log(
8871
- error3("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
9090
+ error2("Refusing to overwrite existing decantr.essence.json in brownfield attach mode.")
8872
9091
  );
8873
9092
  console.log(
8874
9093
  dim3(
@@ -8879,7 +9098,7 @@ async function cmdInit(args) {
8879
9098
  return;
8880
9099
  }
8881
9100
  if (policy.workflowMode === "brownfield-attach" && readBrownfieldProposal(projectRoot)) {
8882
- console.log(error3("Observed brownfield proposal found, but it was not accepted."));
9101
+ console.log(error2("Observed brownfield proposal found, but it was not accepted."));
8883
9102
  console.log(
8884
9103
  dim3(
8885
9104
  "Review `.decantr/brownfield-report.md`, then run `decantr init --existing --accept-proposal`."
@@ -8900,7 +9119,7 @@ async function cmdInit(args) {
8900
9119
  console.log(dim3(` Seeded offline registry content from ${offlineSeed.strategy}.`));
8901
9120
  } else if (requestedBlueprint || requestedArchetype) {
8902
9121
  console.log(
8903
- error3("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
9122
+ error2("\nOffline blueprint/archetype scaffolding requires a local Decantr content source.")
8904
9123
  );
8905
9124
  console.log(
8906
9125
  dim3(
@@ -8968,7 +9187,7 @@ ${YELLOW10}You're offline. Scaffolding minimal Decantr project.${RESET16}`);
8968
9187
  }
8969
9188
  if (requestedBlueprint || requestedArchetype) {
8970
9189
  console.log(
8971
- error3(
9190
+ error2(
8972
9191
  "\nThe requested blueprint/archetype could not be resolved from the hosted registry or local cache."
8973
9192
  )
8974
9193
  );
@@ -9157,7 +9376,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9157
9376
  }
9158
9377
  } else {
9159
9378
  if (requestedBlueprint) {
9160
- console.log(error3(` Error: Could not fetch blueprint "${options.blueprint}".`));
9379
+ console.log(error2(` Error: Could not fetch blueprint "${options.blueprint}".`));
9161
9380
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9162
9381
  process.exitCode = 1;
9163
9382
  return;
@@ -9172,7 +9391,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9172
9391
  archetypeData = mapRegistryArchetypeToArchetypeData(archetypeResult.data);
9173
9392
  } else {
9174
9393
  if (requestedArchetype) {
9175
- console.log(error3(` Error: Could not fetch archetype "${options.archetype}".`));
9394
+ console.log(error2(` Error: Could not fetch archetype "${options.archetype}".`));
9176
9395
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9177
9396
  process.exitCode = 1;
9178
9397
  return;
@@ -9189,7 +9408,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9189
9408
  themeData = mapRegistryThemeToThemeData(themeResult.data);
9190
9409
  } else {
9191
9410
  if (requestedTheme) {
9192
- console.log(error3(` Error: Could not fetch theme "${options.theme}".`));
9411
+ console.log(error2(` Error: Could not fetch theme "${options.theme}".`));
9193
9412
  console.log(dim3("Resolve local registry content or retry against the hosted registry."));
9194
9413
  process.exitCode = 1;
9195
9414
  return;
@@ -9299,7 +9518,7 @@ ${YELLOW10}You're offline. Scaffolding Decantr default.${RESET16}`);
9299
9518
  const essence = JSON.parse(essenceContent);
9300
9519
  const validation = validateEssence2(essence);
9301
9520
  if (!validation.valid) {
9302
- console.log(error3(`
9521
+ console.log(error2(`
9303
9522
  Validation warnings: ${validation.errors.join(", ")}`));
9304
9523
  }
9305
9524
  console.log("");
@@ -9349,13 +9568,12 @@ Validation warnings: ${validation.errors.join(", ")}`));
9349
9568
  console.log(dim3('Run "decantr sync" when online to get the latest registry content.'));
9350
9569
  }
9351
9570
  }
9352
- async function cmdStatus() {
9353
- const projectRoot = process.cwd();
9571
+ async function cmdStatus(projectRoot = process.cwd()) {
9354
9572
  const essencePath = join31(projectRoot, "decantr.essence.json");
9355
9573
  const projectJsonPath = join31(projectRoot, ".decantr", "project.json");
9356
9574
  console.log(heading2("Decantr Project Status"));
9357
9575
  if (!existsSync29(essencePath)) {
9358
- console.log(`${RED13}No decantr.essence.json found.${RESET16}`);
9576
+ console.log(`${RED12}No decantr.essence.json found.${RESET16}`);
9359
9577
  console.log(dim3('Run "decantr init" to create one.'));
9360
9578
  return;
9361
9579
  }
@@ -9367,7 +9585,7 @@ async function cmdStatus() {
9367
9585
  if (validation.valid) {
9368
9586
  console.log(` ${GREEN16}Valid${RESET16} (${essenceVersion})`);
9369
9587
  } else {
9370
- console.log(` ${RED13}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9588
+ console.log(` ${RED12}Invalid: ${validation.errors.join(", ")}${RESET16}`);
9371
9589
  }
9372
9590
  if (isV49(essence)) {
9373
9591
  const v4 = essence;
@@ -9404,7 +9622,7 @@ async function cmdStatus() {
9404
9622
  console.log(` ${YELLOW10}Run \`decantr migrate --to v4\` to upgrade this project.${RESET16}`);
9405
9623
  }
9406
9624
  } catch (e) {
9407
- console.log(` ${RED13}Error reading essence: ${e.message}${RESET16}`);
9625
+ console.log(` ${RED12}Error reading essence: ${e.message}${RESET16}`);
9408
9626
  }
9409
9627
  console.log("");
9410
9628
  console.log(`${BOLD9}Sync Status:${RESET16}`);
@@ -9450,7 +9668,7 @@ function printVerificationFindings(findings) {
9450
9668
  return;
9451
9669
  }
9452
9670
  for (const finding of findings) {
9453
- const color = finding.severity === "error" ? RED13 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9671
+ const color = finding.severity === "error" ? RED12 : finding.severity === "warn" ? YELLOW10 : CYAN9;
9454
9672
  console.log(
9455
9673
  ` ${color}[${finding.severity.toUpperCase()}]${RESET16} ${finding.category}: ${finding.message}`
9456
9674
  );
@@ -9466,7 +9684,7 @@ function printProjectAuditReport(report) {
9466
9684
  if (report.valid) {
9467
9685
  console.log(success3("Project contract is valid."));
9468
9686
  } else {
9469
- console.log(`${RED13}Project audit found blocking issues.${RESET16}`);
9687
+ console.log(`${RED12}Project audit found blocking issues.${RESET16}`);
9470
9688
  }
9471
9689
  console.log("");
9472
9690
  console.log(`${BOLD9}Summary:${RESET16}`);
@@ -9555,13 +9773,12 @@ async function cmdAudit(filePath) {
9555
9773
  console.log(dim3("Project audit completed with advisory findings."));
9556
9774
  }
9557
9775
  } catch (e) {
9558
- console.log(`${RED13}Error: ${e.message}${RESET16}`);
9776
+ console.log(`${RED12}Error: ${e.message}${RESET16}`);
9559
9777
  process.exitCode = 1;
9560
9778
  }
9561
9779
  }
9562
- async function cmdTheme(args) {
9780
+ async function cmdTheme(args, projectRoot = process.cwd()) {
9563
9781
  const subcommand = args[0];
9564
- const projectRoot = process.cwd();
9565
9782
  if (!subcommand || subcommand === "help") {
9566
9783
  console.log(`
9567
9784
  ${BOLD9}decantr theme${RESET16} \u2014 Manage custom themes
@@ -9586,7 +9803,7 @@ ${BOLD9}Examples:${RESET16}
9586
9803
  case "create": {
9587
9804
  const name = args[1];
9588
9805
  if (!name) {
9589
- console.error(error3("Usage: decantr theme create <name>"));
9806
+ console.error(error2("Usage: decantr theme create <name>"));
9590
9807
  process.exitCode = 1;
9591
9808
  return;
9592
9809
  }
@@ -9598,7 +9815,7 @@ ${BOLD9}Examples:${RESET16}
9598
9815
  console.log("");
9599
9816
  console.log(`Use in essence: ${cyan3(`"id": "custom:${name}"`)}`);
9600
9817
  } else {
9601
- console.error(error3(result.error || "Failed to create theme"));
9818
+ console.error(error2(result.error || "Failed to create theme"));
9602
9819
  process.exitCode = 1;
9603
9820
  }
9604
9821
  break;
@@ -9619,13 +9836,13 @@ ${BOLD9}Examples:${RESET16}
9619
9836
  case "validate": {
9620
9837
  const name = args[1];
9621
9838
  if (!name) {
9622
- console.error(error3("Usage: decantr theme validate <name>"));
9839
+ console.error(error2("Usage: decantr theme validate <name>"));
9623
9840
  process.exitCode = 1;
9624
9841
  return;
9625
9842
  }
9626
9843
  const themePath = join31(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
9627
9844
  if (!existsSync29(themePath)) {
9628
- console.error(error3(`Theme "${name}" not found at ${themePath}`));
9845
+ console.error(error2(`Theme "${name}" not found at ${themePath}`));
9629
9846
  process.exitCode = 1;
9630
9847
  return;
9631
9848
  }
@@ -9635,14 +9852,14 @@ ${BOLD9}Examples:${RESET16}
9635
9852
  if (result.valid) {
9636
9853
  console.log(success3(`Custom theme "${name}" is valid`));
9637
9854
  } else {
9638
- console.error(error3("Validation failed:"));
9855
+ console.error(error2("Validation failed:"));
9639
9856
  for (const err of result.errors) {
9640
- console.error(` ${RED13}${err}${RESET16}`);
9857
+ console.error(` ${RED12}${err}${RESET16}`);
9641
9858
  }
9642
9859
  process.exitCode = 1;
9643
9860
  }
9644
9861
  } catch (e) {
9645
- console.error(error3(`Invalid JSON: ${e.message}`));
9862
+ console.error(error2(`Invalid JSON: ${e.message}`));
9646
9863
  process.exitCode = 1;
9647
9864
  }
9648
9865
  break;
@@ -9650,7 +9867,7 @@ ${BOLD9}Examples:${RESET16}
9650
9867
  case "delete": {
9651
9868
  const name = args[1];
9652
9869
  if (!name) {
9653
- console.error(error3("Usage: decantr theme delete <name>"));
9870
+ console.error(error2("Usage: decantr theme delete <name>"));
9654
9871
  process.exitCode = 1;
9655
9872
  return;
9656
9873
  }
@@ -9658,7 +9875,7 @@ ${BOLD9}Examples:${RESET16}
9658
9875
  if (result.success) {
9659
9876
  console.log(success3(`Deleted custom theme "${name}"`));
9660
9877
  } else {
9661
- console.error(error3(result.error || "Failed to delete theme"));
9878
+ console.error(error2(result.error || "Failed to delete theme"));
9662
9879
  process.exitCode = 1;
9663
9880
  }
9664
9881
  break;
@@ -9666,7 +9883,7 @@ ${BOLD9}Examples:${RESET16}
9666
9883
  case "import": {
9667
9884
  const sourcePath = args[1];
9668
9885
  if (!sourcePath) {
9669
- console.error(error3("Usage: decantr theme import <path>"));
9886
+ console.error(error2("Usage: decantr theme import <path>"));
9670
9887
  process.exitCode = 1;
9671
9888
  return;
9672
9889
  }
@@ -9675,9 +9892,9 @@ ${BOLD9}Examples:${RESET16}
9675
9892
  console.log(success3("Theme imported successfully"));
9676
9893
  console.log(dim3(` Path: ${result.path}`));
9677
9894
  } else {
9678
- console.error(error3("Import failed:"));
9895
+ console.error(error2("Import failed:"));
9679
9896
  for (const err of result.errors || []) {
9680
- console.error(` ${RED13}${err}${RESET16}`);
9897
+ console.error(` ${RED12}${err}${RESET16}`);
9681
9898
  }
9682
9899
  process.exitCode = 1;
9683
9900
  }
@@ -9686,7 +9903,7 @@ ${BOLD9}Examples:${RESET16}
9686
9903
  case "switch": {
9687
9904
  const name = args[1];
9688
9905
  if (!name) {
9689
- console.error(error3("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9906
+ console.error(error2("Usage: decantr theme switch <themeName> [--shape <s>] [--mode <m>]"));
9690
9907
  process.exitCode = 1;
9691
9908
  return;
9692
9909
  }
@@ -9694,7 +9911,7 @@ ${BOLD9}Examples:${RESET16}
9694
9911
  break;
9695
9912
  }
9696
9913
  default:
9697
- console.error(error3(`Unknown theme command: ${subcommand}`));
9914
+ console.error(error2(`Unknown theme command: ${subcommand}`));
9698
9915
  process.exitCode = 1;
9699
9916
  }
9700
9917
  }
@@ -9761,13 +9978,55 @@ function withoutWorkflowOnlyFlags(args) {
9761
9978
  function withProject(command, projectArg) {
9762
9979
  return projectArg ? `${command} --project ${projectArg}` : command;
9763
9980
  }
9981
+ function displayProjectPath(workspaceInfo, projectPath) {
9982
+ const absolutePath = join31(workspaceInfo.appRoot, projectPath);
9983
+ const relativePath = relative7(workspaceInfo.cwd, absolutePath).replace(/\\/g, "/");
9984
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute3(relativePath)) {
9985
+ return relativePath;
9986
+ }
9987
+ return absolutePath;
9988
+ }
9989
+ function stripProjectArgs(args, startIndex = 1) {
9990
+ const stripped = [args[0]];
9991
+ for (let index = startIndex; index < args.length; index += 1) {
9992
+ const arg = args[index];
9993
+ if (arg === "--project" && args[index + 1]) {
9994
+ index += 1;
9995
+ continue;
9996
+ }
9997
+ if (arg.startsWith("--project=")) continue;
9998
+ stripped.push(arg);
9999
+ }
10000
+ return stripped;
10001
+ }
10002
+ function normalizedProjectPath(value) {
10003
+ if (!value) return null;
10004
+ return value.replace(/\\/g, "/").replace(/\/+$/g, "");
10005
+ }
10006
+ function printProjectNotFound(projectArg, commandName) {
10007
+ console.error(error2(`decantr ${commandName} could not find project path: ${projectArg}`));
10008
+ console.error(dim3("Pass an existing app path, for example `--project apps/web`."));
10009
+ }
10010
+ function ensureAllowedFlags(flags, allowed, commandName) {
10011
+ const allowedSet = new Set(allowed);
10012
+ const unknown = Object.keys(flags).filter((flag) => !allowedSet.has(flag));
10013
+ if (unknown.length === 0) return true;
10014
+ console.error(error2(`Unsupported option for decantr ${commandName}: --${unknown[0]}`));
10015
+ console.error(dim3("Run `decantr help` or the command-specific help to see supported options."));
10016
+ process.exitCode = 1;
10017
+ return false;
10018
+ }
10019
+ function compilePacksCommandForProject(projectArg) {
10020
+ const essencePath = projectArg ? `${projectArg}/decantr.essence.json` : "decantr.essence.json";
10021
+ return `decantr registry compile-packs ${essencePath} --write-context`;
10022
+ }
9764
10023
  function firstWorkspaceCandidate(workspaceInfo) {
9765
10024
  return workspaceInfo.appCandidates[0] ?? "apps/web";
9766
10025
  }
9767
10026
  function printWorkspaceProjectSelection(workspaceInfo, commandName = "command") {
9768
10027
  const candidate = firstWorkspaceCandidate(workspaceInfo);
9769
10028
  const noun = commandName === "adopt" ? "Brownfield adoption" : `decantr ${commandName}`;
9770
- console.log(error3(`${noun} needs an app path.`));
10029
+ console.log(error2(`${noun} needs an app path.`));
9771
10030
  console.log("");
9772
10031
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9773
10032
  console.log("Install Decantr at the workspace root, then attach it to one app with --project.");
@@ -9787,10 +10046,47 @@ function printWorkspaceProjectSelection(workspaceInfo, commandName = "command")
9787
10046
  }
9788
10047
  function printMonorepoSetupGuidance(workspaceInfo) {
9789
10048
  const candidate = firstWorkspaceCandidate(workspaceInfo);
10049
+ const attachedProjects = workspaceInfo.appCandidates.filter(
10050
+ (appCandidate) => existsSync29(join31(workspaceInfo.workspaceRoot, appCandidate, "decantr.essence.json"))
10051
+ );
10052
+ const firstAttached = attachedProjects[0];
9790
10053
  console.log(heading2("Decantr Setup"));
9791
10054
  console.log(`${BOLD9}This looks like a monorepo.${RESET16}`);
9792
10055
  console.log(` Workspace root: ${workspaceInfo.workspaceRoot}`);
9793
10056
  console.log("");
10057
+ if (firstAttached) {
10058
+ console.log("Decantr is already attached to at least one app.");
10059
+ console.log("");
10060
+ console.log("Attached projects:");
10061
+ for (const project of attachedProjects) {
10062
+ console.log(` ${project}`);
10063
+ }
10064
+ console.log("");
10065
+ console.log(`${BOLD9}Next:${RESET16}`);
10066
+ console.log(
10067
+ ` ${cyan3(`decantr doctor --project ${firstAttached}`)} Explain current state and next command`
10068
+ );
10069
+ console.log(
10070
+ ` ${cyan3(`decantr task <route> "<change>" --project ${firstAttached}`)} Prepare LLM context before edits`
10071
+ );
10072
+ console.log(
10073
+ ` ${cyan3(`decantr verify --brownfield --local-patterns --project ${firstAttached}`)} Check after edits`
10074
+ );
10075
+ console.log(
10076
+ ` ${cyan3(`decantr ci init --project ${firstAttached}`)} Wire the app into CI`
10077
+ );
10078
+ const unattached = workspaceInfo.appCandidates.filter(
10079
+ (appCandidate) => !attachedProjects.includes(appCandidate)
10080
+ );
10081
+ if (unattached.length > 0) {
10082
+ console.log("");
10083
+ console.log("Other app candidates:");
10084
+ for (const appCandidate of unattached) {
10085
+ console.log(` ${appCandidate}`);
10086
+ }
10087
+ }
10088
+ return;
10089
+ }
9794
10090
  console.log(
9795
10091
  "Install Decantr at the workspace root, then attach it to the app you want Decantr to govern."
9796
10092
  );
@@ -9816,9 +10112,34 @@ function printMonorepoSetupGuidance(workspaceInfo) {
9816
10112
  ` ${cyan3(`decantr verify --project ${candidate} --base-url http://localhost:3000 --evidence`)}`
9817
10113
  );
9818
10114
  }
9819
- function resolveWorkflowProject(flags, commandName = "command") {
10115
+ function resolveWorkflowProject(flags, commandName = "command", options = {}) {
9820
10116
  const projectArg = flagString(flags, "project");
9821
10117
  const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
10118
+ if (projectArg && options.requireExisting !== false && !existsSync29(workspaceInfo.appRoot)) {
10119
+ printProjectNotFound(projectArg, commandName);
10120
+ process.exitCode = 1;
10121
+ return null;
10122
+ }
10123
+ if (projectArg && options.requireAppCandidate && workspaceInfo.appCandidates.length > 0) {
10124
+ const normalizedProject = normalizedProjectPath(projectArg);
10125
+ const knownCandidate = normalizedProject ? workspaceInfo.appCandidates.includes(normalizedProject) : false;
10126
+ const forcePackage = flagBoolean(flags, "force-package") || flagBoolean(flags, "allow-package") || flagBoolean(flags, "force");
10127
+ if (!knownCandidate && !forcePackage && !options.allowPackageProject) {
10128
+ console.error(
10129
+ error2(`decantr ${commandName} is app-scoped, but "${projectArg}" is not an app candidate.`)
10130
+ );
10131
+ if (workspaceInfo.appCandidates.length > 0) {
10132
+ console.error(dim3(`App candidates: ${workspaceInfo.appCandidates.join(", ")}`));
10133
+ }
10134
+ console.error(
10135
+ dim3(
10136
+ "Use --force-package only if you intentionally want Decantr attached to a non-app package."
10137
+ )
10138
+ );
10139
+ process.exitCode = 1;
10140
+ return null;
10141
+ }
10142
+ }
9822
10143
  if (workspaceInfo.requiresProjectSelection) {
9823
10144
  printWorkspaceProjectSelection(workspaceInfo, commandName);
9824
10145
  process.exitCode = 1;
@@ -9887,7 +10208,37 @@ async function cmdSetupWorkflow(args) {
9887
10208
  }
9888
10209
  async function cmdAdoptWorkflow(args) {
9889
10210
  const { flags } = parseLooseArgs(args);
9890
- const workspaceInfo = resolveWorkflowProject(flags, "adopt");
10211
+ if (!ensureAllowedFlags(
10212
+ flags,
10213
+ [
10214
+ "project",
10215
+ "dry-run",
10216
+ "yes",
10217
+ "y",
10218
+ "base-url",
10219
+ "verify",
10220
+ "browser",
10221
+ "evidence",
10222
+ "baseline",
10223
+ "save-baseline",
10224
+ "packs",
10225
+ "skip-packs",
10226
+ "offline",
10227
+ "ci",
10228
+ "init-ci",
10229
+ "assistant-bridge",
10230
+ "replace-essence",
10231
+ "merge-proposal",
10232
+ "telemetry",
10233
+ "force-package",
10234
+ "allow-package",
10235
+ "force"
10236
+ ],
10237
+ "adopt"
10238
+ )) {
10239
+ return;
10240
+ }
10241
+ const workspaceInfo = resolveWorkflowProject(flags, "adopt", { requireAppCandidate: true });
9891
10242
  if (!workspaceInfo) return;
9892
10243
  const projectRoot = workspaceInfo.appRoot;
9893
10244
  const projectArg = flagString(flags, "project");
@@ -9898,6 +10249,7 @@ async function cmdAdoptWorkflow(args) {
9898
10249
  const runBrowser = flagBoolean(flags, "browser") || Boolean(baseUrl);
9899
10250
  const evidence = flagBoolean(flags, "evidence") || runBrowser;
9900
10251
  const saveBaseline = flagBoolean(flags, "baseline", true) || flagBoolean(flags, "save-baseline");
10252
+ const hydratePacks = flagBoolean(flags, "packs", true) && !flagBoolean(flags, "skip-packs") && !flagBoolean(flags, "offline") && process.env.DECANTR_OFFLINE !== "true";
9901
10253
  const initCi = flagBoolean(flags, "ci") || flagBoolean(flags, "init-ci");
9902
10254
  const assistantBridge = flagString(flags, "assistant-bridge");
9903
10255
  const hasEssence = existsSync29(join31(projectRoot, "decantr.essence.json"));
@@ -9906,6 +10258,9 @@ async function cmdAdoptWorkflow(args) {
9906
10258
  "analyze current app and write .decantr/brownfield intelligence",
9907
10259
  `init --existing ${proposalFlag} as contract-only Brownfield`
9908
10260
  ];
10261
+ if (hydratePacks) {
10262
+ steps.push("hydrate hosted execution packs into the app context");
10263
+ }
9909
10264
  if (runVerify) {
9910
10265
  steps.push(
9911
10266
  runBrowser ? "verify with Project Health, browser evidence, visual manifest, and baseline" : "verify with Project Health and baseline"
@@ -9939,8 +10294,33 @@ async function cmdAdoptWorkflow(args) {
9939
10294
  telemetry: flagBoolean(flags, "telemetry")
9940
10295
  });
9941
10296
  if (process.exitCode && process.exitCode !== 0) return;
10297
+ if (hydratePacks) {
10298
+ try {
10299
+ const { bundle, contextDir } = await compileHostedExecutionPackBundle(
10300
+ join31(projectRoot, "decantr.essence.json")
10301
+ );
10302
+ const written = writeHostedExecutionPackContextArtifacts(
10303
+ contextDir,
10304
+ bundle
10305
+ );
10306
+ console.log(
10307
+ success3(
10308
+ `Hydrated Decantr execution packs (${written.paths.length} files) into ${contextDir}.`
10309
+ )
10310
+ );
10311
+ } catch (e) {
10312
+ console.log(`${YELLOW10}Pack hydration skipped:${RESET16} ${e.message}`);
10313
+ console.log(
10314
+ dim3(
10315
+ `Run ${compilePacksCommandForProject(projectArg)} after adoption if you want hosted page/review packs.`
10316
+ )
10317
+ );
10318
+ }
10319
+ } else if (flagBoolean(flags, "offline") || process.env.DECANTR_OFFLINE === "true") {
10320
+ console.log(dim3("Skipping hosted pack hydration in offline mode."));
10321
+ }
9942
10322
  if (runVerify) {
9943
- const { cmdHealth } = await import("./health-Q7XF3I5Z.js");
10323
+ const { cmdHealth } = await import("./health-MB63O56B.js");
9944
10324
  await cmdHealth(projectRoot, {
9945
10325
  browser: runBrowser,
9946
10326
  browserBaseUrl: baseUrl,
@@ -9975,13 +10355,43 @@ async function cmdAdoptWorkflow(args) {
9975
10355
  }
9976
10356
  async function cmdVerifyWorkflow(args) {
9977
10357
  const { flags } = parseLooseArgs(args);
10358
+ const projectArg = flagString(flags, "project");
10359
+ if (!ensureAllowedFlags(
10360
+ flags,
10361
+ [
10362
+ "project",
10363
+ "workspace",
10364
+ "changed",
10365
+ "since",
10366
+ "json",
10367
+ "markdown",
10368
+ "format",
10369
+ "output",
10370
+ "ci",
10371
+ "fail-on",
10372
+ "prompt",
10373
+ "brownfield",
10374
+ "local-patterns",
10375
+ "evidence",
10376
+ "browser",
10377
+ "require-browser",
10378
+ "base-url",
10379
+ "design-tokens",
10380
+ "save-baseline",
10381
+ "since-baseline",
10382
+ "baseline"
10383
+ ],
10384
+ "verify"
10385
+ )) {
10386
+ return;
10387
+ }
9978
10388
  const workspaceMode = flagBoolean(flags, "workspace");
9979
10389
  if (args[1] === "init-ci") {
9980
10390
  await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
9981
10391
  return;
9982
10392
  }
9983
10393
  if (workspaceMode) {
9984
- const { cmdWorkspace } = await import("./workspace-JA2RZI6V.js");
10394
+ const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
9985
10395
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
9986
10396
  return;
9987
10397
  }
@@ -10024,7 +10434,7 @@ async function cmdVerifyWorkflow(args) {
10024
10434
  process.exitCode = void 0;
10025
10435
  }
10026
10436
  }
10027
- const { cmdHealth, parseHealthArgs } = await import("./health-Q7XF3I5Z.js");
10437
+ const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
10028
10438
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
10029
10439
  if (localPatterns) {
10030
10440
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -10032,7 +10442,7 @@ async function cmdVerifyWorkflow(args) {
10032
10442
  if (!quietOutput) {
10033
10443
  console.log("");
10034
10444
  console.log(
10035
- `${YELLOW10}Local pattern pack missing.${RESET16} Run ${cyan3("decantr codify --from-audit")}, review the proposal, then run ${cyan3("decantr codify --accept")}.`
10445
+ `${YELLOW10}Local pattern pack missing.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))}, review the proposal, then run ${cyan3(withProject("decantr codify --accept", projectArg))}.`
10036
10446
  );
10037
10447
  }
10038
10448
  process.exitCode = process.exitCode || 1;
@@ -10090,10 +10500,11 @@ async function cmdTaskWorkflow(args) {
10090
10500
  const { flags, positional } = parseLooseArgs(args);
10091
10501
  const workspaceInfo = resolveWorkflowProject(flags, "task");
10092
10502
  if (!workspaceInfo) return;
10503
+ const projectArg = flagString(flags, "project");
10093
10504
  const routeInput = positional[0];
10094
10505
  if (!routeInput) {
10095
10506
  console.error(
10096
- error3(
10507
+ error2(
10097
10508
  'Usage: decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]'
10098
10509
  )
10099
10510
  );
@@ -10106,20 +10517,20 @@ async function cmdTaskWorkflow(args) {
10106
10517
  const essence = readJsonIfPresent(essencePath);
10107
10518
  if (!essence) {
10108
10519
  console.error(
10109
- error3("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10520
+ error2("No decantr.essence.json found. Run `decantr adopt` or `decantr init` first.")
10110
10521
  );
10111
10522
  process.exitCode = 1;
10112
10523
  return;
10113
10524
  }
10114
10525
  if (!isV49(essence)) {
10115
- console.error(error3("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10526
+ console.error(error2("Task context requires Essence v4. Run `decantr migrate --to v4` first."));
10116
10527
  process.exitCode = 1;
10117
10528
  return;
10118
10529
  }
10119
10530
  const target = essence.blueprint.routes?.[route];
10120
10531
  if (!target) {
10121
10532
  const knownRoutes = Object.keys(essence.blueprint.routes ?? {}).sort();
10122
- console.error(error3(`Route not found in Decantr contract: ${route}`));
10533
+ console.error(error2(`Route not found in Decantr contract: ${route}`));
10123
10534
  console.error(dim3(`Known routes: ${knownRoutes.join(", ") || "none"}`));
10124
10535
  process.exitCode = 1;
10125
10536
  return;
@@ -10135,6 +10546,11 @@ async function cmdTaskWorkflow(args) {
10135
10546
  const localPatternPackPath = localPatternsPath(workspaceInfo.appRoot);
10136
10547
  const localRuleManifestPath = localRulesPath(workspaceInfo.appRoot);
10137
10548
  const localLaw = createLocalLawTaskSummary(workspaceInfo.appRoot);
10549
+ const displayedLocalLaw = {
10550
+ ...localLaw,
10551
+ patternsPath: localLaw.patternsPath ? displayProjectPath(workspaceInfo, localLaw.patternsPath) : null,
10552
+ rulesPath: localLaw.rulesPath ? displayProjectPath(workspaceInfo, localLaw.rulesPath) : null
10553
+ };
10138
10554
  const changedSince = flagString(flags, "since");
10139
10555
  const currentChangedFiles = changedFiles(workspaceInfo.appRoot, changedSince);
10140
10556
  const changedRoutes = routeImpacts(workspaceInfo.appRoot, currentChangedFiles);
@@ -10146,19 +10562,19 @@ async function cmdTaskWorkflow(args) {
10146
10562
  shell: page?.shell ?? section?.shell ?? null,
10147
10563
  patterns: page?.layout?.map(extractPatternName) ?? [],
10148
10564
  read: [
10149
- pagePack ? join31(".decantr/context", pagePack.markdown) : null,
10150
- sectionPack ? join31(".decantr/context", sectionPack.markdown) : null,
10151
- manifest?.scaffold?.markdown ? join31(".decantr/context", manifest.scaffold.markdown) : null,
10152
- ".decantr/context/scaffold.md",
10153
- "DECANTR.md",
10154
- existsSync29(localPatternPackPath) ? ".decantr/local-patterns.json" : null,
10155
- existsSync29(localRuleManifestPath) ? ".decantr/rules.json" : null
10565
+ pagePack ? displayProjectPath(workspaceInfo, join31(".decantr/context", pagePack.markdown)) : null,
10566
+ sectionPack ? displayProjectPath(workspaceInfo, join31(".decantr/context", sectionPack.markdown)) : null,
10567
+ manifest?.scaffold?.markdown ? displayProjectPath(workspaceInfo, join31(".decantr/context", manifest.scaffold.markdown)) : null,
10568
+ displayProjectPath(workspaceInfo, ".decantr/context/scaffold.md"),
10569
+ displayProjectPath(workspaceInfo, "DECANTR.md"),
10570
+ existsSync29(localPatternPackPath) ? displayProjectPath(workspaceInfo, ".decantr/local-patterns.json") : null,
10571
+ existsSync29(localRuleManifestPath) ? displayProjectPath(workspaceInfo, ".decantr/rules.json") : null
10156
10572
  ].filter(Boolean),
10157
- screenshot: screenshot ?? null,
10158
- localLaw,
10573
+ screenshot: screenshot?.startsWith(".decantr/") ? displayProjectPath(workspaceInfo, screenshot) : screenshot ?? null,
10574
+ localLaw: displayedLocalLaw,
10159
10575
  changedFiles: currentChangedFiles,
10160
10576
  changedRoutes,
10161
- verifyCommand: "decantr verify --brownfield --local-patterns"
10577
+ verifyCommand: withProject("decantr verify --brownfield --local-patterns", projectArg)
10162
10578
  };
10163
10579
  if (flagBoolean(flags, "json")) {
10164
10580
  console.log(JSON.stringify(context, null, 2));
@@ -10199,7 +10615,7 @@ async function cmdTaskWorkflow(args) {
10199
10615
  console.log("");
10200
10616
  console.log(`${BOLD9}Project-owned local law:${RESET16}`);
10201
10617
  console.log(
10202
- ` ${YELLOW10}Not codified yet.${RESET16} Run ${cyan3("decantr codify --from-audit")} after adoption.`
10618
+ ` ${YELLOW10}Not codified yet.${RESET16} Run ${cyan3(withProject("decantr codify --from-audit", projectArg))} after adoption.`
10203
10619
  );
10204
10620
  }
10205
10621
  if (context.changedFiles.length > 0) {
@@ -10224,12 +10640,20 @@ async function cmdTaskWorkflow(args) {
10224
10640
  }
10225
10641
  async function cmdCodifyWorkflow(args) {
10226
10642
  const { flags } = parseLooseArgs(args);
10643
+ const projectArg = flagString(flags, "project");
10644
+ if (!ensureAllowedFlags(
10645
+ flags,
10646
+ ["project", "from-audit", "discover-local-patterns", "codify-local-patterns", "accept"],
10647
+ "codify"
10648
+ )) {
10649
+ return;
10650
+ }
10227
10651
  const workspaceInfo = resolveWorkflowProject(flags, "codify");
10228
10652
  if (!workspaceInfo) return;
10229
10653
  if (flagBoolean(flags, "accept")) {
10230
10654
  if (!existsSync29(localPatternsProposalPath(workspaceInfo.appRoot)) && !existsSync29(localRulesProposalPath(workspaceInfo.appRoot))) {
10231
10655
  console.error(
10232
- error3(
10656
+ error2(
10233
10657
  "No local law proposal found. Run `decantr codify --from-audit` or `decantr codify` first."
10234
10658
  )
10235
10659
  );
@@ -10243,7 +10667,11 @@ async function cmdCodifyWorkflow(args) {
10243
10667
  if (result2.rulesAcceptedPath) {
10244
10668
  console.log(success3(`Accepted local rule manifest: ${result2.rulesAcceptedPath}`));
10245
10669
  }
10246
- console.log(dim3("Run `decantr verify --brownfield --local-patterns` after project edits."));
10670
+ console.log(
10671
+ dim3(
10672
+ `Run \`${withProject("decantr verify --brownfield --local-patterns", projectArg)}\` after project edits.`
10673
+ )
10674
+ );
10247
10675
  return;
10248
10676
  }
10249
10677
  const detected = detectProject(workspaceInfo.appRoot);
@@ -10267,7 +10695,7 @@ async function cmdCodifyWorkflow(args) {
10267
10695
  }
10268
10696
  console.log(
10269
10697
  dim3(
10270
- "Review both files, add real component paths/token recipes, then run `decantr codify --accept`."
10698
+ `Review both files, add real component paths/token recipes, then run \`${withProject("decantr codify --accept", projectArg)}\`.`
10271
10699
  )
10272
10700
  );
10273
10701
  }
@@ -10282,10 +10710,12 @@ async function cmdContentWorkflow(args) {
10282
10710
  return;
10283
10711
  }
10284
10712
  if (subcommand === "create") {
10713
+ const { flags } = parseLooseArgs(args);
10714
+ if (!ensureAllowedFlags(flags, [], "content create")) return;
10285
10715
  const type = args[2];
10286
10716
  const name = args[3];
10287
10717
  if (!type || !name) {
10288
- console.error(error3("Usage: decantr content create <type> <name>"));
10718
+ console.error(error2("Usage: decantr content create <type> <name>"));
10289
10719
  process.exitCode = 1;
10290
10720
  return;
10291
10721
  }
@@ -10293,17 +10723,19 @@ async function cmdContentWorkflow(args) {
10293
10723
  return;
10294
10724
  }
10295
10725
  if (subcommand === "publish") {
10726
+ const { flags } = parseLooseArgs(args);
10727
+ if (!ensureAllowedFlags(flags, [], "content publish")) return;
10296
10728
  const type = args[2];
10297
10729
  const name = args[3];
10298
10730
  if (!type || !name) {
10299
- console.error(error3("Usage: decantr content publish <type> <name>"));
10731
+ console.error(error2("Usage: decantr content publish <type> <name>"));
10300
10732
  process.exitCode = 1;
10301
10733
  return;
10302
10734
  }
10303
10735
  await cmdPublish(type, name);
10304
10736
  return;
10305
10737
  }
10306
- console.error(error3("Usage: decantr content <check|create|publish>"));
10738
+ console.error(error2("Usage: decantr content <check|create|publish>"));
10307
10739
  process.exitCode = 1;
10308
10740
  }
10309
10741
  function cmdHelp() {
@@ -10313,7 +10745,7 @@ ${BOLD9}decantr${RESET16} \u2014 Design intelligence for AI-generated UI
10313
10745
  ${BOLD9}Usage:${RESET16}
10314
10746
  decantr setup [--project <path>]
10315
10747
  decantr new <name> [--blueprint=X] [--archetype=X] [--theme=X] [--workflow=greenfield] [--adoption=decantr-css] [--telemetry]
10316
- decantr adopt [--project <path>] [--base-url <url>] [--evidence] [--ci] [--yes]
10748
+ decantr adopt [--project <path>] [--base-url <url>] [--evidence] [--ci] [--no-packs] [--yes]
10317
10749
  decantr task <route> ["task summary"] [--project <path>] [--since origin/main] [--json]
10318
10750
  decantr verify [--project <path>] [--brownfield] [--local-patterns] [health options]
10319
10751
  decantr ci [--project <path>] [--workspace] [--fail-on error|warn|none]
@@ -10673,11 +11105,11 @@ ${BOLD9}Examples:${RESET16}
10673
11105
  }
10674
11106
  function cmdAdoptHelp() {
10675
11107
  console.log(`
10676
- ${BOLD9}decantr adopt${RESET16} \u2014 Brownfield one-liner: analyze, attach, verify, and show the operating loop
11108
+ ${BOLD9}decantr adopt${RESET16} \u2014 Brownfield one-liner: analyze, attach, hydrate packs, verify, and show the operating loop
10677
11109
 
10678
11110
  ${BOLD9}Usage:${RESET16}
10679
- decantr adopt [--project <path>] [--yes] [--dry-run]
10680
- decantr adopt [--project <path>] --base-url <url> [--evidence] [--ci] [--yes]
11111
+ decantr adopt [--project <path>] [--yes] [--dry-run] [--no-packs]
11112
+ decantr adopt [--project <path>] --base-url <url> [--evidence] [--ci] [--yes] [--no-packs]
10681
11113
 
10682
11114
  ${BOLD9}Options:${RESET16}
10683
11115
  --project App path inside a workspace/monorepo
@@ -10688,6 +11120,7 @@ ${BOLD9}Options:${RESET16}
10688
11120
  --baseline Save a health baseline (default)
10689
11121
  --no-baseline Skip baseline save
10690
11122
  --no-verify Skip the verification step
11123
+ --no-packs Skip hosted execution-pack hydration
10691
11124
  --ci, --init-ci Install the Decantr CI gate after adoption
10692
11125
  --telemetry Opt this project into privacy-filtered CLI product telemetry
10693
11126
  --merge-proposal Merge the observed proposal into an existing essence
@@ -10838,10 +11271,10 @@ async function main() {
10838
11271
  }
10839
11272
  }
10840
11273
  }
10841
- console.error(error3("Could not resolve @decantr/cli version from package.json."));
11274
+ console.error(error2("Could not resolve @decantr/cli version from package.json."));
10842
11275
  process.exitCode = 1;
10843
11276
  } catch (e) {
10844
- console.error(error3(`Failed to read CLI version: ${e.message}`));
11277
+ console.error(error2(`Failed to read CLI version: ${e.message}`));
10845
11278
  process.exitCode = 1;
10846
11279
  }
10847
11280
  return;
@@ -10886,7 +11319,7 @@ async function main() {
10886
11319
  const newName = args[1];
10887
11320
  if (!newName) {
10888
11321
  console.error(
10889
- error3("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
11322
+ error2("Usage: decantr new <project-name> [--blueprint=X] [--archetype=X] [--theme=X]")
10890
11323
  );
10891
11324
  process.exitCode = 1;
10892
11325
  break;
@@ -10958,7 +11391,10 @@ async function main() {
10958
11391
  break;
10959
11392
  }
10960
11393
  case "status": {
10961
- await cmdStatus();
11394
+ const { flags } = parseLooseArgs(args);
11395
+ const workspaceInfo = resolveWorkflowProject(flags, "status");
11396
+ if (!workspaceInfo) break;
11397
+ await cmdStatus(workspaceInfo.appRoot);
10962
11398
  break;
10963
11399
  }
10964
11400
  case "sync": {
@@ -10967,8 +11403,11 @@ async function main() {
10967
11403
  }
10968
11404
  case "upgrade": {
10969
11405
  const { cmdUpgrade } = await import("./upgrade-VON7Y3LG.js");
11406
+ const { flags } = parseLooseArgs(args);
11407
+ const workspaceInfo = resolveWorkflowProject(flags, "upgrade");
11408
+ if (!workspaceInfo) break;
10970
11409
  const applyFlag = args.includes("--apply");
10971
- await cmdUpgrade(process.cwd(), { apply: applyFlag });
11410
+ await cmdUpgrade(workspaceInfo.appRoot, { apply: applyFlag });
10972
11411
  break;
10973
11412
  }
10974
11413
  case "check":
@@ -10984,7 +11423,10 @@ async function main() {
10984
11423
  if (!workspaceInfo) break;
10985
11424
  const telemetryFlag = args.includes("--telemetry");
10986
11425
  const brownfieldFlag = args.includes("--brownfield");
10987
- await cmdHeal(workspaceInfo.appRoot, { telemetry: telemetryFlag, brownfield: brownfieldFlag });
11426
+ await cmdHeal(workspaceInfo.appRoot, {
11427
+ telemetry: telemetryFlag,
11428
+ brownfield: brownfieldFlag
11429
+ });
10988
11430
  break;
10989
11431
  }
10990
11432
  case "health": {
@@ -10993,10 +11435,17 @@ async function main() {
10993
11435
  cmdHealthHelp();
10994
11436
  break;
10995
11437
  }
10996
- const { cmdHealth, parseHealthArgs } = await import("./health-Q7XF3I5Z.js");
10997
- await cmdHealth(process.cwd(), parseHealthArgs(args));
11438
+ if (args[1] === "init-ci") {
11439
+ await cmdCi(["ci", "init", ...args.slice(2)], process.cwd());
11440
+ break;
11441
+ }
11442
+ const { flags } = parseLooseArgs(args);
11443
+ const workspaceInfo = resolveWorkflowProject(flags, "health");
11444
+ if (!workspaceInfo) break;
11445
+ const { cmdHealth, parseHealthArgs } = await import("./health-MB63O56B.js");
11446
+ await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
10998
11447
  } catch (e) {
10999
- console.error(error3(e.message));
11448
+ console.error(error2(e.message));
11000
11449
  process.exitCode = 1;
11001
11450
  }
11002
11451
  break;
@@ -11010,7 +11459,7 @@ async function main() {
11010
11459
  const { cmdContentHealth, parseContentHealthArgs } = await import("./content-health-4KP2EGTI.js");
11011
11460
  await cmdContentHealth(process.cwd(), parseContentHealthArgs(args));
11012
11461
  } catch (e) {
11013
- console.error(error3(e.message));
11462
+ console.error(error2(e.message));
11014
11463
  process.exitCode = 1;
11015
11464
  }
11016
11465
  break;
@@ -11021,10 +11470,10 @@ async function main() {
11021
11470
  cmdStudioHelp();
11022
11471
  break;
11023
11472
  }
11024
- const { cmdStudio, parseStudioArgs } = await import("./studio-EDQMI6JE.js");
11473
+ const { cmdStudio, parseStudioArgs } = await import("./studio-6QGXJBVH.js");
11025
11474
  await cmdStudio(process.cwd(), parseStudioArgs(args));
11026
11475
  } catch (e) {
11027
- console.error(error3(e.message));
11476
+ console.error(error2(e.message));
11028
11477
  process.exitCode = 1;
11029
11478
  }
11030
11479
  break;
@@ -11035,10 +11484,10 @@ async function main() {
11035
11484
  cmdWorkspaceHelp();
11036
11485
  break;
11037
11486
  }
11038
- const { cmdWorkspace } = await import("./workspace-JA2RZI6V.js");
11487
+ const { cmdWorkspace } = await import("./workspace-OGFYJA4N.js");
11039
11488
  await cmdWorkspace(process.cwd(), args);
11040
11489
  } catch (e) {
11041
- console.error(error3(e.message));
11490
+ console.error(error2(e.message));
11042
11491
  process.exitCode = 1;
11043
11492
  }
11044
11493
  break;
@@ -11061,7 +11510,7 @@ async function main() {
11061
11510
  if (result.success) {
11062
11511
  console.log(success3(clearFlag ? "Drift log cleared." : "Entries resolved."));
11063
11512
  } else {
11064
- console.error(error3(result.error || "Failed"));
11513
+ console.error(error2(result.error || "Failed"));
11065
11514
  process.exitCode = 1;
11066
11515
  }
11067
11516
  } else {
@@ -11077,7 +11526,7 @@ async function main() {
11077
11526
  const query = args[1];
11078
11527
  if (!query) {
11079
11528
  console.error(
11080
- error3(
11529
+ error2(
11081
11530
  "Usage: decantr search <query> [--type <type>] [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11082
11531
  )
11083
11532
  );
@@ -11095,7 +11544,7 @@ async function main() {
11095
11544
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11096
11545
  if (rawBlueprintSet && !blueprintSet) {
11097
11546
  console.error(
11098
- error3(
11547
+ error2(
11099
11548
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11100
11549
  )
11101
11550
  );
@@ -11104,7 +11553,7 @@ async function main() {
11104
11553
  }
11105
11554
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11106
11555
  console.error(
11107
- error3(
11556
+ error2(
11108
11557
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11109
11558
  )
11110
11559
  );
@@ -11116,31 +11565,51 @@ async function main() {
11116
11565
  break;
11117
11566
  }
11118
11567
  case "suggest": {
11119
- const query = args[1];
11568
+ const { flags, positional } = parseLooseArgs(args);
11569
+ if (!ensureAllowedFlags(flags, ["type", "route", "file", "from-code", "project"], "suggest")) {
11570
+ break;
11571
+ }
11572
+ const projectArg = flagString(flags, "project");
11573
+ const route = flagString(flags, "route");
11574
+ let file = flagString(flags, "file");
11575
+ const normalizedProject = normalizedProjectPath(projectArg);
11576
+ if (file && normalizedProject && normalizedProjectPath(file)?.startsWith(`${normalizedProject}/`)) {
11577
+ file = normalizedProjectPath(file)?.slice(normalizedProject.length + 1);
11578
+ }
11579
+ const fromCode = flagBoolean(flags, "from-code");
11580
+ let query = positional.join(" ").trim();
11581
+ if (!query && (route || file || fromCode)) {
11582
+ query = [
11583
+ route ? `route ${route}` : null,
11584
+ file ? `file ${basename3(file)}` : null,
11585
+ fromCode ? "source code patterns" : null
11586
+ ].filter((entry) => Boolean(entry)).join(" ");
11587
+ }
11120
11588
  if (!query) {
11121
11589
  console.error(
11122
- error3(
11123
- "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code]"
11590
+ error2(
11591
+ "Usage: decantr suggest <query> [--type <type>] [--route <route>] [--file <path>] [--from-code] [--project <path>]"
11124
11592
  )
11125
11593
  );
11126
11594
  process.exitCode = 1;
11127
11595
  return;
11128
11596
  }
11129
- const typeIdx = args.indexOf("--type");
11130
- const type = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
11131
- const routeIdx = args.indexOf("--route");
11132
- const route = routeIdx !== -1 ? args[routeIdx + 1] : void 0;
11133
- const fileIdx = args.indexOf("--file");
11134
- const file = fileIdx !== -1 ? args[fileIdx + 1] : void 0;
11135
- const fromCode = args.includes("--from-code");
11136
- await cmdSuggest(query, { type, route, file, fromCode });
11597
+ const workspaceInfo = projectArg ? resolveWorkflowProject(flags, "suggest") : null;
11598
+ if (projectArg && !workspaceInfo) break;
11599
+ await cmdSuggest(query, {
11600
+ type: flagString(flags, "type"),
11601
+ route,
11602
+ file,
11603
+ fromCode,
11604
+ projectRoot: workspaceInfo?.appRoot
11605
+ });
11137
11606
  break;
11138
11607
  }
11139
11608
  case "get": {
11140
11609
  const type = args[1];
11141
11610
  const id = args[2];
11142
11611
  if (!type || !id) {
11143
- console.error(error3("Usage: decantr get <type> <id>"));
11612
+ console.error(error2("Usage: decantr get <type> <id>"));
11144
11613
  process.exitCode = 1;
11145
11614
  return;
11146
11615
  }
@@ -11151,7 +11620,7 @@ async function main() {
11151
11620
  const type = args[1];
11152
11621
  if (!type) {
11153
11622
  console.error(
11154
- error3(
11623
+ error2(
11155
11624
  "Usage: decantr list <type> [--sort <recommended|recent|name>] [--source <authored|benchmark|hybrid>] [--blueprint-set <all|featured|certified|labs>]"
11156
11625
  )
11157
11626
  );
@@ -11167,7 +11636,7 @@ async function main() {
11167
11636
  const blueprintSet = rawBlueprintSet && isPublicBlueprintSet(rawBlueprintSet) ? rawBlueprintSet : void 0;
11168
11637
  if (rawBlueprintSet && !blueprintSet) {
11169
11638
  console.error(
11170
- error3(
11639
+ error2(
11171
11640
  `Invalid blueprint set "${rawBlueprintSet}". Must be one of: all, featured, certified, labs.`
11172
11641
  )
11173
11642
  );
@@ -11176,7 +11645,7 @@ async function main() {
11176
11645
  }
11177
11646
  if (intelligenceSource && !isContentIntelligenceSource(intelligenceSource)) {
11178
11647
  console.error(
11179
- error3(
11648
+ error2(
11180
11649
  `Invalid source "${intelligenceSource}". Must be one of: authored, benchmark, hybrid.`
11181
11650
  )
11182
11651
  );
@@ -11196,7 +11665,7 @@ async function main() {
11196
11665
  break;
11197
11666
  }
11198
11667
  if (requestedView && !["manifest", "shortlist", "verification"].includes(requestedView)) {
11199
- console.error(error3("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11668
+ console.error(error2("Usage: decantr showcase [manifest|shortlist|verification] [--json]"));
11200
11669
  process.exitCode = 1;
11201
11670
  break;
11202
11671
  }
@@ -11208,7 +11677,10 @@ async function main() {
11208
11677
  break;
11209
11678
  }
11210
11679
  case "theme": {
11211
- await cmdTheme(args.slice(1));
11680
+ const { flags } = parseLooseArgs(args);
11681
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "theme") : null;
11682
+ if (flagString(flags, "project") && !workspaceInfo) break;
11683
+ await cmdTheme(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11212
11684
  break;
11213
11685
  }
11214
11686
  case "login": {
@@ -11242,14 +11714,19 @@ async function main() {
11242
11714
  break;
11243
11715
  }
11244
11716
  case "telemetry": {
11245
- await cmdTelemetry(args.slice(1), process.cwd());
11717
+ const { flags } = parseLooseArgs(args);
11718
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "telemetry") : null;
11719
+ if (flagString(flags, "project") && !workspaceInfo) break;
11720
+ await cmdTelemetry(stripProjectArgs(args).slice(1), workspaceInfo?.appRoot ?? process.cwd());
11246
11721
  break;
11247
11722
  }
11248
11723
  case "create": {
11724
+ const { flags } = parseLooseArgs(args);
11725
+ if (!ensureAllowedFlags(flags, [], "create")) break;
11249
11726
  const type = args[1];
11250
11727
  const name = args[2];
11251
11728
  if (!type || !name) {
11252
- console.error(error3("Usage: decantr create <type> <name>"));
11729
+ console.error(error2("Usage: decantr create <type> <name>"));
11253
11730
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11254
11731
  process.exitCode = 1;
11255
11732
  break;
@@ -11258,10 +11735,12 @@ async function main() {
11258
11735
  break;
11259
11736
  }
11260
11737
  case "publish": {
11738
+ const { flags } = parseLooseArgs(args);
11739
+ if (!ensureAllowedFlags(flags, [], "publish")) break;
11261
11740
  const type = args[1];
11262
11741
  const name = args[2];
11263
11742
  if (!type || !name) {
11264
- console.error(error3("Usage: decantr publish <type> <name>"));
11743
+ console.error(error2("Usage: decantr publish <type> <name>"));
11265
11744
  console.error(dim3("Types: pattern, theme, blueprint, archetype, shell"));
11266
11745
  process.exitCode = 1;
11267
11746
  break;
@@ -11278,7 +11757,8 @@ async function main() {
11278
11757
  offline: refreshOffline,
11279
11758
  check: args.includes("--check"),
11280
11759
  listChanges: args.includes("--list-changes"),
11281
- json: args.includes("--json")
11760
+ json: args.includes("--json"),
11761
+ displayRoot: workspaceInfo.cwd
11282
11762
  });
11283
11763
  break;
11284
11764
  }
@@ -11313,7 +11793,7 @@ async function main() {
11313
11793
  let id = args[3] && !args[3].startsWith("--") ? args[3] : void 0;
11314
11794
  if (!packType || !["manifest", "scaffold", "review", "section", "page", "mutation"].includes(packType)) {
11315
11795
  console.error(
11316
- `${RED13}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11796
+ `${RED12}Usage: decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context]${RESET16}`
11317
11797
  );
11318
11798
  process.exitCode = 1;
11319
11799
  break;
@@ -11345,7 +11825,7 @@ async function main() {
11345
11825
  const sourcePath = args[2] && !args[2].startsWith("--") ? args[2] : void 0;
11346
11826
  if (!sourcePath) {
11347
11827
  console.error(
11348
- `${RED13}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11828
+ `${RED12}Usage: decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>]${RESET16}`
11349
11829
  );
11350
11830
  process.exitCode = 1;
11351
11831
  break;
@@ -11370,16 +11850,20 @@ async function main() {
11370
11850
  await printHostedProjectAudit(namespace, jsonOutput, essencePath, distPath, sourcesPath);
11371
11851
  } else {
11372
11852
  console.error(
11373
- `${RED13}Usage: decantr registry mirror [--type <type>] | decantr registry summary [--namespace <namespace>] [--json] | decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context] | decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context] | decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>] | decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]${RESET16}`
11853
+ `${RED12}Usage: decantr registry mirror [--type <type>] | decantr registry summary [--namespace <namespace>] [--json] | decantr registry compile-packs [path] [--namespace <namespace>] [--json] [--write-context] | decantr registry get-pack <manifest|scaffold|review|section|page|mutation> [id] [--namespace <namespace>] [--json] [--essence <path>] [--write-context] | decantr registry critique-file <file> [--namespace <namespace>] [--json] [--essence <path>] [--treatments <path>] | decantr registry audit-project [--namespace <namespace>] [--json] [--essence <path>] [--dist <path>] [--sources <dir>]${RESET16}`
11374
11854
  );
11375
11855
  process.exitCode = 1;
11376
11856
  }
11377
11857
  break;
11378
11858
  }
11379
11859
  case "add": {
11860
+ const { flags } = parseLooseArgs(args);
11861
+ if (!ensureAllowedFlags(flags, ["project", "route", "section"], "add")) break;
11862
+ const workspaceInfo = resolveWorkflowProject(flags, "add");
11863
+ if (!workspaceInfo) break;
11380
11864
  const subcommand = args[1];
11381
11865
  if (!subcommand) {
11382
- console.error(error3("Usage: decantr add <section|page|feature> <target>"));
11866
+ console.error(error2("Usage: decantr add <section|page|feature> <target>"));
11383
11867
  process.exitCode = 1;
11384
11868
  break;
11385
11869
  }
@@ -11387,45 +11871,49 @@ async function main() {
11387
11871
  case "section": {
11388
11872
  const id = args[2];
11389
11873
  if (!id) {
11390
- console.error(error3("Usage: decantr add section <archetypeId>"));
11874
+ console.error(error2("Usage: decantr add section <archetypeId>"));
11391
11875
  process.exitCode = 1;
11392
11876
  break;
11393
11877
  }
11394
- await cmdAddSection(id, args, process.cwd());
11878
+ await cmdAddSection(id, args, workspaceInfo.appRoot);
11395
11879
  break;
11396
11880
  }
11397
11881
  case "page": {
11398
11882
  const pagePath = args[2];
11399
11883
  if (!pagePath) {
11400
- console.error(error3("Usage: decantr add page <section>/<page>"));
11884
+ console.error(error2("Usage: decantr add page <section>/<page>"));
11401
11885
  process.exitCode = 1;
11402
11886
  break;
11403
11887
  }
11404
- await cmdAddPage(pagePath, args, process.cwd());
11888
+ await cmdAddPage(pagePath, args, workspaceInfo.appRoot);
11405
11889
  break;
11406
11890
  }
11407
11891
  case "feature": {
11408
11892
  const feature = args[2];
11409
11893
  if (!feature) {
11410
- console.error(error3("Usage: decantr add feature <feature> [--section <id>]"));
11894
+ console.error(error2("Usage: decantr add feature <feature> [--section <id>]"));
11411
11895
  process.exitCode = 1;
11412
11896
  break;
11413
11897
  }
11414
- await cmdAddFeature(feature, args, process.cwd());
11898
+ await cmdAddFeature(feature, args, workspaceInfo.appRoot);
11415
11899
  break;
11416
11900
  }
11417
11901
  default:
11418
11902
  console.error(
11419
- error3(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11903
+ error2(`Unknown add subcommand: ${subcommand}. Use section, page, or feature.`)
11420
11904
  );
11421
11905
  process.exitCode = 1;
11422
11906
  }
11423
11907
  break;
11424
11908
  }
11425
11909
  case "remove": {
11910
+ const { flags } = parseLooseArgs(args);
11911
+ if (!ensureAllowedFlags(flags, ["project", "section"], "remove")) break;
11912
+ const workspaceInfo = resolveWorkflowProject(flags, "remove");
11913
+ if (!workspaceInfo) break;
11426
11914
  const subcommand = args[1];
11427
11915
  if (!subcommand) {
11428
- console.error(error3("Usage: decantr remove <section|page|feature> <target>"));
11916
+ console.error(error2("Usage: decantr remove <section|page|feature> <target>"));
11429
11917
  process.exitCode = 1;
11430
11918
  break;
11431
11919
  }
@@ -11433,56 +11921,54 @@ async function main() {
11433
11921
  case "section": {
11434
11922
  const id = args[2];
11435
11923
  if (!id) {
11436
- console.error(error3("Usage: decantr remove section <sectionId>"));
11924
+ console.error(error2("Usage: decantr remove section <sectionId>"));
11437
11925
  process.exitCode = 1;
11438
11926
  break;
11439
11927
  }
11440
- await cmdRemoveSection(id, args, process.cwd());
11928
+ await cmdRemoveSection(id, args, workspaceInfo.appRoot);
11441
11929
  break;
11442
11930
  }
11443
11931
  case "page": {
11444
11932
  const pagePath = args[2];
11445
11933
  if (!pagePath) {
11446
- console.error(error3("Usage: decantr remove page <section>/<page>"));
11934
+ console.error(error2("Usage: decantr remove page <section>/<page>"));
11447
11935
  process.exitCode = 1;
11448
11936
  break;
11449
11937
  }
11450
- await cmdRemovePage(pagePath, args, process.cwd());
11938
+ await cmdRemovePage(pagePath, args, workspaceInfo.appRoot);
11451
11939
  break;
11452
11940
  }
11453
11941
  case "feature": {
11454
11942
  const feature = args[2];
11455
11943
  if (!feature) {
11456
- console.error(error3("Usage: decantr remove feature <feature> [--section <id>]"));
11944
+ console.error(error2("Usage: decantr remove feature <feature> [--section <id>]"));
11457
11945
  process.exitCode = 1;
11458
11946
  break;
11459
11947
  }
11460
- await cmdRemoveFeature(feature, args, process.cwd());
11948
+ await cmdRemoveFeature(feature, args, workspaceInfo.appRoot);
11461
11949
  break;
11462
11950
  }
11463
11951
  default:
11464
11952
  console.error(
11465
- error3(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11953
+ error2(`Unknown remove subcommand: ${subcommand}. Use section, page, or feature.`)
11466
11954
  );
11467
11955
  process.exitCode = 1;
11468
11956
  }
11469
11957
  break;
11470
11958
  }
11471
11959
  case "analyze": {
11472
- let projectArg;
11473
- for (let i = 1; i < args.length; i++) {
11474
- if (args[i].startsWith("--project=")) {
11475
- projectArg = args[i].split("=")[1];
11476
- } else if (args[i] === "--project" && args[i + 1]) {
11477
- projectArg = args[++i];
11478
- }
11479
- }
11480
- const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
11481
- if (workspaceInfo.requiresProjectSelection) {
11482
- printWorkspaceProjectSelection(workspaceInfo, "analyze");
11483
- process.exitCode = 1;
11960
+ const { flags } = parseLooseArgs(args);
11961
+ if (!ensureAllowedFlags(
11962
+ flags,
11963
+ ["project", "force-package", "allow-package", "force"],
11964
+ "analyze"
11965
+ )) {
11484
11966
  break;
11485
11967
  }
11968
+ const workspaceInfo = resolveWorkflowProject(flags, "analyze", {
11969
+ requireAppCandidate: true
11970
+ });
11971
+ if (!workspaceInfo) break;
11486
11972
  await cmdAnalyze(workspaceInfo.appRoot, workspaceInfo);
11487
11973
  break;
11488
11974
  }
@@ -11493,24 +11979,14 @@ async function main() {
11493
11979
  break;
11494
11980
  }
11495
11981
  if (subcommand !== "apply" && subcommand !== "preview") {
11496
- console.error(error3("Usage: decantr rules <preview|apply> [--project=<path>]"));
11497
- process.exitCode = 1;
11498
- break;
11499
- }
11500
- let projectArg;
11501
- for (let i = 2; i < args.length; i++) {
11502
- if (args[i].startsWith("--project=")) {
11503
- projectArg = args[i].split("=")[1];
11504
- } else if (args[i] === "--project" && args[i + 1]) {
11505
- projectArg = args[++i];
11506
- }
11507
- }
11508
- const workspaceInfo = resolveWorkspaceInfo(process.cwd(), projectArg);
11509
- if (workspaceInfo.requiresProjectSelection) {
11510
- printWorkspaceProjectSelection(workspaceInfo, "rules");
11982
+ console.error(error2("Usage: decantr rules <preview|apply> [--project=<path>]"));
11511
11983
  process.exitCode = 1;
11512
11984
  break;
11513
11985
  }
11986
+ const { flags } = parseLooseArgs(args);
11987
+ if (!ensureAllowedFlags(flags, ["project"], "rules")) break;
11988
+ const workspaceInfo = resolveWorkflowProject(flags, "rules");
11989
+ if (!workspaceInfo) break;
11514
11990
  const detected = detectProject(workspaceInfo.appRoot);
11515
11991
  if (subcommand === "preview") {
11516
11992
  console.log(
@@ -11531,24 +12007,18 @@ async function main() {
11531
12007
  break;
11532
12008
  }
11533
12009
  case "magic": {
11534
- const magicFlags = {};
11535
- const promptParts = [];
11536
- for (let i = 1; i < args.length; i++) {
11537
- if (args[i] === "--dry-run") {
11538
- magicFlags.dryRun = true;
11539
- } else if (args[i] === "--offline") {
11540
- magicFlags.offline = true;
11541
- } else if (args[i].startsWith("--registry=")) {
11542
- magicFlags.registry = args[i].split("=")[1];
11543
- } else if (args[i].startsWith("--registry") && args[i + 1]) {
11544
- magicFlags.registry = args[++i];
11545
- } else {
11546
- promptParts.push(args[i]);
11547
- }
12010
+ const { flags, positional } = parseLooseArgs(args);
12011
+ if (!ensureAllowedFlags(flags, ["dry-run", "offline", "registry", "project"], "magic")) {
12012
+ break;
11548
12013
  }
11549
- const magicPrompt = promptParts.join(" ").trim();
12014
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "magic") : null;
12015
+ if (flagString(flags, "project") && !workspaceInfo) break;
12016
+ const projectArg = flagString(flags, "project");
12017
+ const magicPrompt = positional.join(" ").trim();
11550
12018
  if (!magicPrompt) {
11551
- console.error(error3("Usage: decantr magic <prompt> [--dry-run] [--offline]"));
12019
+ console.error(
12020
+ error2("Usage: decantr magic <prompt> [--dry-run] [--offline] [--project <path>]")
12021
+ );
11552
12022
  console.error("");
11553
12023
  console.error(" Example:");
11554
12024
  console.error(
@@ -11557,38 +12027,34 @@ async function main() {
11557
12027
  process.exitCode = 1;
11558
12028
  break;
11559
12029
  }
11560
- await cmdMagic(magicPrompt, process.cwd(), {
11561
- dryRun: magicFlags.dryRun,
11562
- offline: magicFlags.offline,
11563
- registry: magicFlags.registry
12030
+ await cmdMagic(magicPrompt, workspaceInfo?.appRoot ?? process.cwd(), {
12031
+ dryRun: flagBoolean(flags, "dry-run"),
12032
+ offline: flagBoolean(flags, "offline"),
12033
+ registry: flagString(flags, "registry"),
12034
+ projectLabel: projectArg
11564
12035
  });
11565
12036
  break;
11566
12037
  }
11567
12038
  case "export": {
11568
- let exportTarget;
11569
- let exportOutput;
11570
- for (let i = 1; i < args.length; i++) {
11571
- if (args[i] === "--to" && args[i + 1]) {
11572
- exportTarget = args[++i];
11573
- } else if (args[i].startsWith("--to=")) {
11574
- exportTarget = args[i].split("=")[1];
11575
- } else if (args[i] === "--output" && args[i + 1]) {
11576
- exportOutput = args[++i];
11577
- } else if (args[i].startsWith("--output=")) {
11578
- exportOutput = args[i].split("=")[1];
11579
- }
11580
- }
12039
+ const { flags } = parseLooseArgs(args);
12040
+ if (!ensureAllowedFlags(flags, ["to", "output", "project"], "export")) break;
12041
+ const workspaceInfo = flagString(flags, "project") ? resolveWorkflowProject(flags, "export") : null;
12042
+ if (flagString(flags, "project") && !workspaceInfo) break;
12043
+ const exportTarget = flagString(flags, "to");
12044
+ const exportOutput = flagString(flags, "output");
11581
12045
  const validTargets = ["shadcn", "tailwind", "css-vars", "figma-tokens"];
11582
12046
  if (!exportTarget || !validTargets.includes(exportTarget)) {
11583
- console.error(error3(`Usage: decantr export --to <${validTargets.join("|")}>`));
12047
+ console.error(error2(`Usage: decantr export --to <${validTargets.join("|")}>`));
11584
12048
  process.exitCode = 1;
11585
12049
  break;
11586
12050
  }
11587
- await cmdExport(exportTarget, process.cwd(), { output: exportOutput });
12051
+ await cmdExport(exportTarget, workspaceInfo?.appRoot ?? process.cwd(), {
12052
+ output: exportOutput
12053
+ });
11588
12054
  break;
11589
12055
  }
11590
12056
  default:
11591
- console.error(error3(`Unknown command: ${command}`));
12057
+ console.error(error2(`Unknown command: ${command}`));
11592
12058
  cmdHelp();
11593
12059
  process.exitCode = 1;
11594
12060
  }
@@ -11603,7 +12069,7 @@ main().then(async () => {
11603
12069
  success: !process.exitCode || process.exitCode === 0
11604
12070
  });
11605
12071
  }).catch(async (e) => {
11606
- console.error(error3(e.message));
12072
+ console.error(error2(e.message));
11607
12073
  if (e.stack) console.error(e.stack);
11608
12074
  process.exitCode = 1;
11609
12075
  await sendCliCommandTelemetry({