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