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