@decantr/cli 1.7.6 → 1.7.7
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 +51 -3
- package/dist/bin.js +2 -2
- package/dist/{chunk-H4H3IQJK.js → chunk-4D5V6GQU.js} +75 -10
- package/dist/{chunk-KAEQTVAM.js → chunk-OHQXL7EJ.js} +468 -330
- package/dist/index.js +2 -2
- package/dist/{upgrade-XNUAON3G.js → upgrade-WE7Y7ZOE.js} +1 -1
- package/package.json +4 -2
- package/src/templates/DECANTR.md.template +4 -0
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
scaffoldProject,
|
|
15
15
|
syncRegistry,
|
|
16
16
|
writeExecutionPackBundleArtifacts
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4D5V6GQU.js";
|
|
18
18
|
import {
|
|
19
19
|
buildGuardRegistryContext
|
|
20
20
|
} from "./chunk-KUDAVJOR.js";
|
|
21
21
|
|
|
22
22
|
// src/index.ts
|
|
23
|
-
import { mkdirSync as
|
|
24
|
-
import { basename, join as
|
|
23
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as writeFileSync13, existsSync as existsSync25, readdirSync as readdirSync6 } from "fs";
|
|
24
|
+
import { basename as basename2, join as join26, dirname as dirname2, isAbsolute, resolve as resolve3 } from "path";
|
|
25
25
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
26
26
|
import { validateEssence as validateEssence2, evaluateGuard, isV3 as isV36 } from "@decantr/essence-spec";
|
|
27
27
|
import {
|
|
@@ -238,7 +238,7 @@ ${CYAN}Detected project configuration:${RESET}`);
|
|
|
238
238
|
console.log(` Existing essence: ${YELLOW}yes${RESET}`);
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
-
async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
241
|
+
async function runInteractivePrompts(detected, archetypes, blueprints, themes, workflowSeed) {
|
|
242
242
|
showDetection(detected);
|
|
243
243
|
const blueprintOptions = [
|
|
244
244
|
{ value: "none", label: "none", description: "Start from scratch (blank canvas)" },
|
|
@@ -255,7 +255,8 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
255
255
|
label: t.id,
|
|
256
256
|
description: t.description
|
|
257
257
|
}));
|
|
258
|
-
const
|
|
258
|
+
const desiredTheme = workflowSeed?.theme || "luminarum";
|
|
259
|
+
const defaultThemeIdx = Math.max(0, themeOptions.findIndex((t) => t.value === desiredTheme));
|
|
259
260
|
const theme = await select("Choose a theme", themeOptions, Math.max(0, defaultThemeIdx), true);
|
|
260
261
|
const mode = await select(
|
|
261
262
|
"Color mode",
|
|
@@ -264,7 +265,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
264
265
|
{ value: "light", label: "light", description: "Light background" },
|
|
265
266
|
{ value: "auto", label: "auto", description: "Follow system preference" }
|
|
266
267
|
],
|
|
267
|
-
0
|
|
268
|
+
workflowSeed?.mode === "light" ? 1 : workflowSeed?.mode === "auto" ? 2 : 0
|
|
268
269
|
);
|
|
269
270
|
const shape = await select(
|
|
270
271
|
"Border shape",
|
|
@@ -286,7 +287,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
286
287
|
{ value: "angular", label: "angular", description: "Angular" },
|
|
287
288
|
{ value: "html", label: "html", description: "Plain HTML/CSS/JS" }
|
|
288
289
|
];
|
|
289
|
-
let defaultFrameworkIdx = frameworkOptions.findIndex((f) => f.value === detected.framework);
|
|
290
|
+
let defaultFrameworkIdx = frameworkOptions.findIndex((f) => f.value === (workflowSeed?.target || detected.framework));
|
|
290
291
|
if (defaultFrameworkIdx < 0) defaultFrameworkIdx = 0;
|
|
291
292
|
const target = await select("Target framework", frameworkOptions, defaultFrameworkIdx, true);
|
|
292
293
|
if (detected.framework !== "unknown" && target !== detected.framework) {
|
|
@@ -303,8 +304,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
303
304
|
{ value: "guided", label: "guided", description: "Style, structure, density enforced" },
|
|
304
305
|
{ value: "strict", label: "strict", description: "All 5 rules enforced exactly" }
|
|
305
306
|
],
|
|
306
|
-
detected.existingEssence ? 1 : 2
|
|
307
|
-
// Default to guided for existing, strict for new
|
|
307
|
+
workflowSeed?.guard === "creative" ? 0 : workflowSeed?.guard === "strict" ? 2 : workflowSeed?.guard === "guided" ? 1 : detected.existingEssence ? 1 : 2
|
|
308
308
|
);
|
|
309
309
|
const density = await select(
|
|
310
310
|
"Spacing density",
|
|
@@ -313,7 +313,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
313
313
|
{ value: "comfortable", label: "comfortable", description: "Balanced spacing" },
|
|
314
314
|
{ value: "spacious", label: "spacious", description: "Generous whitespace" }
|
|
315
315
|
],
|
|
316
|
-
1
|
|
316
|
+
workflowSeed?.density === "compact" ? 0 : workflowSeed?.density === "spacious" ? 2 : 1
|
|
317
317
|
);
|
|
318
318
|
const shellOptions = [
|
|
319
319
|
{ value: "sidebar-main", label: "sidebar-main", description: "Collapsible sidebar with main content" },
|
|
@@ -322,8 +322,11 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
322
322
|
{ value: "full-bleed", label: "full-bleed", description: "No persistent nav (landing pages)" },
|
|
323
323
|
{ value: "minimal-header", label: "minimal-header", description: "Slim header with centered content" }
|
|
324
324
|
];
|
|
325
|
-
let defaultShellIdx =
|
|
326
|
-
if (
|
|
325
|
+
let defaultShellIdx = shellOptions.findIndex((s) => s.value === workflowSeed?.shell);
|
|
326
|
+
if (defaultShellIdx < 0) {
|
|
327
|
+
defaultShellIdx = 0;
|
|
328
|
+
}
|
|
329
|
+
if (defaultShellIdx === 0 && ["nextjs", "nuxt", "astro"].includes(target)) {
|
|
327
330
|
defaultShellIdx = shellOptions.findIndex((s) => s.value === "top-nav-main");
|
|
328
331
|
}
|
|
329
332
|
const shell = await select("Default page shell (layout)", shellOptions, Math.max(0, defaultShellIdx), true);
|
|
@@ -340,7 +343,7 @@ async function runInteractivePrompts(detected, archetypes, blueprints, themes) {
|
|
|
340
343
|
shell,
|
|
341
344
|
personality: ["professional"],
|
|
342
345
|
features: [],
|
|
343
|
-
existing: detected.existingEssence
|
|
346
|
+
existing: workflowSeed?.existing || detected.existingEssence
|
|
344
347
|
};
|
|
345
348
|
}
|
|
346
349
|
function parseFlags(args, detected) {
|
|
@@ -359,20 +362,20 @@ function parseFlags(args, detected) {
|
|
|
359
362
|
if (args.existing === true) options.existing = true;
|
|
360
363
|
return options;
|
|
361
364
|
}
|
|
362
|
-
function mergeWithDefaults(flags, detected) {
|
|
365
|
+
function mergeWithDefaults(flags, detected, workflowSeed) {
|
|
363
366
|
return {
|
|
364
367
|
blueprint: flags.blueprint,
|
|
365
368
|
archetype: flags.archetype,
|
|
366
|
-
theme: flags.theme || "luminarum",
|
|
367
|
-
mode: flags.mode || "dark",
|
|
369
|
+
theme: flags.theme || workflowSeed?.theme || "luminarum",
|
|
370
|
+
mode: flags.mode || workflowSeed?.mode || "dark",
|
|
368
371
|
shape: flags.shape || "rounded",
|
|
369
|
-
target: flags.target || (detected.framework !== "unknown" ? detected.framework : "react"),
|
|
370
|
-
guard: flags.guard || (detected.existingEssence ? "guided" : "strict"),
|
|
371
|
-
density: flags.density || "comfortable",
|
|
372
|
-
shell: flags.shell || "sidebar-main",
|
|
372
|
+
target: flags.target || workflowSeed?.target || (detected.framework !== "unknown" ? detected.framework : "react"),
|
|
373
|
+
guard: flags.guard || workflowSeed?.guard || (detected.existingEssence ? "guided" : "strict"),
|
|
374
|
+
density: flags.density || workflowSeed?.density || "comfortable",
|
|
375
|
+
shell: flags.shell || workflowSeed?.shell || "sidebar-main",
|
|
373
376
|
personality: flags.personality || ["professional"],
|
|
374
377
|
features: flags.features || [],
|
|
375
|
-
existing: flags.existing || detected.existingEssence
|
|
378
|
+
existing: flags.existing || workflowSeed?.existing || detected.existingEssence
|
|
376
379
|
};
|
|
377
380
|
}
|
|
378
381
|
async function runSimplifiedInit(blueprints) {
|
|
@@ -1532,8 +1535,8 @@ async function cmdThemeSwitch(themeName, args, projectRoot = process.cwd()) {
|
|
|
1532
1535
|
}
|
|
1533
1536
|
|
|
1534
1537
|
// src/commands/analyze.ts
|
|
1535
|
-
import { existsSync as
|
|
1536
|
-
import { join as
|
|
1538
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
1539
|
+
import { join as join19 } from "path";
|
|
1537
1540
|
|
|
1538
1541
|
// src/analyzers/routes.ts
|
|
1539
1542
|
import { existsSync as existsSync12, readdirSync as readdirSync2, statSync } from "fs";
|
|
@@ -2231,6 +2234,53 @@ function scanDependencies(projectRoot) {
|
|
|
2231
2234
|
return result;
|
|
2232
2235
|
}
|
|
2233
2236
|
|
|
2237
|
+
// src/workflow-model.ts
|
|
2238
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
2239
|
+
import { join as join18 } from "path";
|
|
2240
|
+
function inferSuggestedShell(layout) {
|
|
2241
|
+
if (layout.hasSidebar) return "sidebar-main";
|
|
2242
|
+
if (layout.hasTopNav) return "top-nav-main";
|
|
2243
|
+
return "full-bleed";
|
|
2244
|
+
}
|
|
2245
|
+
function hasExistingProjectFootprint(detected) {
|
|
2246
|
+
return detected.framework !== "unknown" || detected.packageManager !== "unknown" || detected.hasTypeScript || detected.hasTailwind || detected.existingRuleFiles.length > 0;
|
|
2247
|
+
}
|
|
2248
|
+
function createBrownfieldInitSeed(detected, layout, styling) {
|
|
2249
|
+
return {
|
|
2250
|
+
version: 1,
|
|
2251
|
+
workflow: "brownfield-adoption",
|
|
2252
|
+
contractOnly: true,
|
|
2253
|
+
registryOptional: true,
|
|
2254
|
+
target: detected.framework !== "unknown" ? detected.framework : "react",
|
|
2255
|
+
shell: inferSuggestedShell(layout),
|
|
2256
|
+
guard: "guided",
|
|
2257
|
+
density: "comfortable",
|
|
2258
|
+
theme: "luminarum",
|
|
2259
|
+
mode: styling.darkMode ? "dark" : "auto",
|
|
2260
|
+
existing: true,
|
|
2261
|
+
notes: [
|
|
2262
|
+
"Use decantr init --existing to attach Decantr contract and context files to this project.",
|
|
2263
|
+
"Registry content is optional during brownfield adoption.",
|
|
2264
|
+
"Use decantr add/remove, decantr theme switch, and registry commands later for hybrid composition."
|
|
2265
|
+
]
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function readBrownfieldInitSeed(projectRoot) {
|
|
2269
|
+
const seedPath = join18(projectRoot, ".decantr", "init-seed.json");
|
|
2270
|
+
if (!existsSync18(seedPath)) {
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
try {
|
|
2274
|
+
const parsed = JSON.parse(readFileSync14(seedPath, "utf-8"));
|
|
2275
|
+
if (parsed.workflow !== "brownfield-adoption") {
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
return parsed;
|
|
2279
|
+
} catch {
|
|
2280
|
+
return null;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2234
2284
|
// src/commands/analyze.ts
|
|
2235
2285
|
var BOLD3 = "\x1B[1m";
|
|
2236
2286
|
var DIM8 = "\x1B[2m";
|
|
@@ -2256,6 +2306,7 @@ ${BOLD3}Analyzing project...${RESET8}
|
|
|
2256
2306
|
const features = scanFeatures(projectRoot);
|
|
2257
2307
|
console.log(`${DIM8}Scanning dependencies...${RESET8}`);
|
|
2258
2308
|
const dependencies = scanDependencies(projectRoot);
|
|
2309
|
+
const initSeed = createBrownfieldInitSeed(project, layout, styling);
|
|
2259
2310
|
const analysis = {
|
|
2260
2311
|
version: 1,
|
|
2261
2312
|
analyzedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2271,14 +2322,29 @@ ${BOLD3}Analyzing project...${RESET8}
|
|
|
2271
2322
|
styling,
|
|
2272
2323
|
layout,
|
|
2273
2324
|
features,
|
|
2274
|
-
dependencies
|
|
2325
|
+
dependencies,
|
|
2326
|
+
decantr: {
|
|
2327
|
+
workflow: "brownfield-adoption",
|
|
2328
|
+
registryOptional: true,
|
|
2329
|
+
attach: {
|
|
2330
|
+
entrypoint: "decantr analyze",
|
|
2331
|
+
contractOnly: true,
|
|
2332
|
+
initSeedPath: ".decantr/init-seed.json",
|
|
2333
|
+
recommendedCommand: "decantr init --existing --yes"
|
|
2334
|
+
},
|
|
2335
|
+
hybrid: {
|
|
2336
|
+
ownerCommands: ["decantr add", "decantr remove", "decantr theme switch", "decantr registry", "decantr upgrade"]
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2275
2339
|
};
|
|
2276
|
-
const decantrDir =
|
|
2277
|
-
if (!
|
|
2340
|
+
const decantrDir = join19(projectRoot, ".decantr");
|
|
2341
|
+
if (!existsSync19(decantrDir)) {
|
|
2278
2342
|
mkdirSync4(decantrDir, { recursive: true });
|
|
2279
2343
|
}
|
|
2280
|
-
const outputPath =
|
|
2344
|
+
const outputPath = join19(decantrDir, "analysis.json");
|
|
2345
|
+
const initSeedPath = join19(decantrDir, "init-seed.json");
|
|
2281
2346
|
writeFileSync9(outputPath, JSON.stringify(analysis, null, 2) + "\n", "utf-8");
|
|
2347
|
+
writeFileSync9(initSeedPath, JSON.stringify(initSeed, null, 2) + "\n", "utf-8");
|
|
2282
2348
|
console.log(`
|
|
2283
2349
|
${GREEN8}Analysis complete.${RESET8}
|
|
2284
2350
|
`);
|
|
@@ -2303,14 +2369,15 @@ ${GREEN8}Analysis complete.${RESET8}
|
|
|
2303
2369
|
console.log(` Dependencies: ${depCounts || "none categorized"}`);
|
|
2304
2370
|
console.log(`
|
|
2305
2371
|
${DIM8}Written to:${RESET8} ${outputPath}`);
|
|
2372
|
+
console.log(`${DIM8}Init seed:${RESET8} ${initSeedPath}`);
|
|
2306
2373
|
console.log(`
|
|
2307
|
-
${YELLOW5}Next step:${RESET8}
|
|
2374
|
+
${YELLOW5}Next step:${RESET8} Run ${BOLD3}decantr init --existing --yes${RESET8} to attach Decantr using the generated brownfield seed.
|
|
2308
2375
|
`);
|
|
2309
2376
|
}
|
|
2310
2377
|
|
|
2311
2378
|
// src/commands/magic.ts
|
|
2312
|
-
import { join as
|
|
2313
|
-
import { existsSync as
|
|
2379
|
+
import { join as join20 } from "path";
|
|
2380
|
+
import { existsSync as existsSync20 } from "fs";
|
|
2314
2381
|
import * as fs from "fs/promises";
|
|
2315
2382
|
var BOLD4 = "\x1B[1m";
|
|
2316
2383
|
var DIM9 = "\x1B[2m";
|
|
@@ -2538,15 +2605,25 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2538
2605
|
console.log(` Archetype: ${intent.archetype}`);
|
|
2539
2606
|
}
|
|
2540
2607
|
console.log("");
|
|
2541
|
-
const essencePath =
|
|
2542
|
-
if (
|
|
2608
|
+
const essencePath = join20(projectRoot, "decantr.essence.json");
|
|
2609
|
+
if (existsSync20(essencePath)) {
|
|
2543
2610
|
console.log(error(" decantr.essence.json already exists in this directory."));
|
|
2544
2611
|
console.log(dim(" Remove it first or use a different directory."));
|
|
2545
2612
|
process.exitCode = 1;
|
|
2546
2613
|
return;
|
|
2547
2614
|
}
|
|
2615
|
+
const detected = detectProject(projectRoot);
|
|
2616
|
+
if (hasExistingProjectFootprint(detected)) {
|
|
2617
|
+
console.log(`${YELLOW6} Existing project detected.${RESET9}`);
|
|
2618
|
+
console.log(dim(" decantr magic stays greenfield-first and will not silently bootstrap over an existing app."));
|
|
2619
|
+
console.log(dim(" Running brownfield analysis instead so you can attach Decantr deliberately.\n"));
|
|
2620
|
+
cmdAnalyze(projectRoot);
|
|
2621
|
+
console.log(`${BOLD4}Recommended next step:${RESET9} ${cyan("decantr init --existing --yes")}`);
|
|
2622
|
+
console.log("");
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2548
2625
|
const registryClient = new RegistryClient({
|
|
2549
|
-
cacheDir:
|
|
2626
|
+
cacheDir: join20(projectRoot, ".decantr", "cache"),
|
|
2550
2627
|
apiUrl: options.registry,
|
|
2551
2628
|
offline: options.offline
|
|
2552
2629
|
});
|
|
@@ -2647,7 +2724,6 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2647
2724
|
return;
|
|
2648
2725
|
}
|
|
2649
2726
|
console.log("");
|
|
2650
|
-
const detected = detectProject(projectRoot);
|
|
2651
2727
|
let archetypeData;
|
|
2652
2728
|
let composedSections;
|
|
2653
2729
|
let routeMap;
|
|
@@ -2809,14 +2885,14 @@ async function cmdMagic(prompt, projectRoot, options) {
|
|
|
2809
2885
|
if (result.gitignoreUpdated) {
|
|
2810
2886
|
console.log(` ${dim(".gitignore updated")}`);
|
|
2811
2887
|
}
|
|
2812
|
-
const contextDir =
|
|
2888
|
+
const contextDir = join20(projectRoot, ".decantr", "context");
|
|
2813
2889
|
let sectionCount = 0;
|
|
2814
2890
|
try {
|
|
2815
2891
|
const files = await fs.readdir(contextDir);
|
|
2816
2892
|
sectionCount = files.filter((f) => f.startsWith("section-")).length;
|
|
2817
2893
|
} catch {
|
|
2818
2894
|
}
|
|
2819
|
-
const treatmentsPath =
|
|
2895
|
+
const treatmentsPath = join20(projectRoot, "src", "styles", "treatments.css");
|
|
2820
2896
|
let hasLayers = false;
|
|
2821
2897
|
try {
|
|
2822
2898
|
const css = await fs.readFile(treatmentsPath, "utf-8");
|
|
@@ -2841,8 +2917,8 @@ ${GREEN9}${BOLD4}Quality summary:${RESET9}`);
|
|
|
2841
2917
|
}
|
|
2842
2918
|
|
|
2843
2919
|
// src/commands/export.ts
|
|
2844
|
-
import { readFileSync as
|
|
2845
|
-
import { join as
|
|
2920
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync10, existsSync as existsSync21, mkdirSync as mkdirSync5 } from "fs";
|
|
2921
|
+
import { join as join21, dirname } from "path";
|
|
2846
2922
|
var GREEN10 = "\x1B[32m";
|
|
2847
2923
|
var RED8 = "\x1B[31m";
|
|
2848
2924
|
var DIM10 = "\x1B[2m";
|
|
@@ -2988,19 +3064,19 @@ function generateCSSVars(tokens) {
|
|
|
2988
3064
|
return lines.join("\n");
|
|
2989
3065
|
}
|
|
2990
3066
|
async function cmdExport(target, projectRoot, options = {}) {
|
|
2991
|
-
const essencePath =
|
|
2992
|
-
const tokensPath =
|
|
2993
|
-
if (!
|
|
3067
|
+
const essencePath = join21(projectRoot, "decantr.essence.json");
|
|
3068
|
+
const tokensPath = join21(projectRoot, "src", "styles", "tokens.css");
|
|
3069
|
+
if (!existsSync21(essencePath)) {
|
|
2994
3070
|
console.error(`${RED8}No decantr.essence.json found. Run \`decantr init\` first.${RESET10}`);
|
|
2995
3071
|
process.exitCode = 1;
|
|
2996
3072
|
return;
|
|
2997
3073
|
}
|
|
2998
|
-
if (!
|
|
3074
|
+
if (!existsSync21(tokensPath)) {
|
|
2999
3075
|
console.error(`${RED8}No src/styles/tokens.css found. Run \`decantr refresh\` to generate tokens.${RESET10}`);
|
|
3000
3076
|
process.exitCode = 1;
|
|
3001
3077
|
return;
|
|
3002
3078
|
}
|
|
3003
|
-
const tokensCSS =
|
|
3079
|
+
const tokensCSS = readFileSync15(tokensPath, "utf-8");
|
|
3004
3080
|
const tokens = parseTokensCSS(tokensCSS);
|
|
3005
3081
|
if (tokens.size === 0) {
|
|
3006
3082
|
console.error(`${RED8}No --d-* tokens found in tokens.css.${RESET10}`);
|
|
@@ -3009,8 +3085,8 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
3009
3085
|
}
|
|
3010
3086
|
switch (target) {
|
|
3011
3087
|
case "shadcn": {
|
|
3012
|
-
const cssOut = options.output ??
|
|
3013
|
-
const jsonOut =
|
|
3088
|
+
const cssOut = options.output ?? join21(projectRoot, "src", "styles", "shadcn-theme.css");
|
|
3089
|
+
const jsonOut = join21(projectRoot, "components.json");
|
|
3014
3090
|
ensureDir(cssOut);
|
|
3015
3091
|
writeFileSync10(cssOut, generateShadcnCSS(tokens), "utf-8");
|
|
3016
3092
|
writeFileSync10(jsonOut, generateShadcnComponentsJSON(), "utf-8");
|
|
@@ -3020,7 +3096,7 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
3020
3096
|
break;
|
|
3021
3097
|
}
|
|
3022
3098
|
case "tailwind": {
|
|
3023
|
-
const out = options.output ??
|
|
3099
|
+
const out = options.output ?? join21(projectRoot, "tailwind.decantr.config.ts");
|
|
3024
3100
|
ensureDir(out);
|
|
3025
3101
|
writeFileSync10(out, generateTailwindConfig(tokens), "utf-8");
|
|
3026
3102
|
console.log(`${GREEN10}Exported Tailwind config:${RESET10}`);
|
|
@@ -3028,7 +3104,7 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
3028
3104
|
break;
|
|
3029
3105
|
}
|
|
3030
3106
|
case "css-vars": {
|
|
3031
|
-
const out = options.output ??
|
|
3107
|
+
const out = options.output ?? join21(projectRoot, "decantr-tokens.css");
|
|
3032
3108
|
ensureDir(out);
|
|
3033
3109
|
writeFileSync10(out, generateCSSVars(tokens), "utf-8");
|
|
3034
3110
|
console.log(`${GREEN10}Exported CSS variables:${RESET10}`);
|
|
@@ -3039,14 +3115,14 @@ async function cmdExport(target, projectRoot, options = {}) {
|
|
|
3039
3115
|
}
|
|
3040
3116
|
function ensureDir(filePath) {
|
|
3041
3117
|
const dir = dirname(filePath);
|
|
3042
|
-
if (!
|
|
3118
|
+
if (!existsSync21(dir)) {
|
|
3043
3119
|
mkdirSync5(dir, { recursive: true });
|
|
3044
3120
|
}
|
|
3045
3121
|
}
|
|
3046
3122
|
|
|
3047
3123
|
// src/commands/registry-mirror.ts
|
|
3048
3124
|
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
3049
|
-
import { join as
|
|
3125
|
+
import { join as join22 } from "path";
|
|
3050
3126
|
import { RegistryAPIClient as RegistryAPIClient2, API_CONTENT_TYPES } from "@decantr/registry";
|
|
3051
3127
|
var GREEN11 = "\x1B[32m";
|
|
3052
3128
|
var RED9 = "\x1B[31m";
|
|
@@ -3074,7 +3150,7 @@ async function cmdRegistryMirror(projectRoot, options = {}) {
|
|
|
3074
3150
|
process.exitCode = 1;
|
|
3075
3151
|
return;
|
|
3076
3152
|
}
|
|
3077
|
-
const cacheDir =
|
|
3153
|
+
const cacheDir = join22(projectRoot, ".decantr", "cache");
|
|
3078
3154
|
const counts = {};
|
|
3079
3155
|
const failed = [];
|
|
3080
3156
|
console.log(`
|
|
@@ -3084,19 +3160,19 @@ Mirroring registry content to ${DIM11}.decantr/cache/${RESET11}
|
|
|
3084
3160
|
try {
|
|
3085
3161
|
const result = await apiClient.listContent(type, { namespace: "@official" });
|
|
3086
3162
|
const items = result.items;
|
|
3087
|
-
const typeDir =
|
|
3163
|
+
const typeDir = join22(cacheDir, "@official", type);
|
|
3088
3164
|
mkdirSync6(typeDir, { recursive: true });
|
|
3089
|
-
writeFileSync11(
|
|
3165
|
+
writeFileSync11(join22(typeDir, "index.json"), JSON.stringify(result, null, 2));
|
|
3090
3166
|
let itemCount = 0;
|
|
3091
3167
|
for (const item of items) {
|
|
3092
3168
|
const slug = item.slug || item.id;
|
|
3093
3169
|
if (!slug) continue;
|
|
3094
3170
|
try {
|
|
3095
3171
|
const fullItem = await apiClient.getContent(type, "@official", slug);
|
|
3096
|
-
writeFileSync11(
|
|
3172
|
+
writeFileSync11(join22(typeDir, `${slug}.json`), JSON.stringify(fullItem, null, 2));
|
|
3097
3173
|
itemCount++;
|
|
3098
3174
|
} catch {
|
|
3099
|
-
writeFileSync11(
|
|
3175
|
+
writeFileSync11(join22(typeDir, `${slug}.json`), JSON.stringify(item, null, 2));
|
|
3100
3176
|
itemCount++;
|
|
3101
3177
|
}
|
|
3102
3178
|
}
|
|
@@ -3111,8 +3187,8 @@ Mirroring registry content to ${DIM11}.decantr/cache/${RESET11}
|
|
|
3111
3187
|
mirrored_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3112
3188
|
counts
|
|
3113
3189
|
};
|
|
3114
|
-
mkdirSync6(
|
|
3115
|
-
writeFileSync11(
|
|
3190
|
+
mkdirSync6(join22(cacheDir), { recursive: true });
|
|
3191
|
+
writeFileSync11(join22(cacheDir, "mirror-manifest.json"), JSON.stringify(manifest, null, 2));
|
|
3116
3192
|
const totalItems = Object.values(counts).reduce((a, b) => a + b, 0);
|
|
3117
3193
|
console.log("");
|
|
3118
3194
|
if (failed.length > 0) {
|
|
@@ -3125,98 +3201,160 @@ Mirroring registry content to ${DIM11}.decantr/cache/${RESET11}
|
|
|
3125
3201
|
}
|
|
3126
3202
|
|
|
3127
3203
|
// src/commands/new-project.ts
|
|
3128
|
-
import { existsSync as
|
|
3129
|
-
import { join as
|
|
3204
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync9 } from "fs";
|
|
3205
|
+
import { join as join25, resolve as resolve2 } from "path";
|
|
3130
3206
|
import { execSync } from "child_process";
|
|
3131
3207
|
import { fileURLToPath } from "url";
|
|
3132
3208
|
|
|
3133
3209
|
// src/offline-content.ts
|
|
3134
|
-
import { cpSync, existsSync as
|
|
3135
|
-
import { join as
|
|
3210
|
+
import { cpSync, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "fs";
|
|
3211
|
+
import { join as join23, resolve } from "path";
|
|
3136
3212
|
var CONTENT_TYPES2 = ["archetypes", "blueprints", "patterns", "themes", "shells"];
|
|
3137
3213
|
function copyIfExists(source, target) {
|
|
3138
|
-
if (!
|
|
3214
|
+
if (!existsSync23(source)) return false;
|
|
3139
3215
|
if (resolve(source) === resolve(target)) return true;
|
|
3140
3216
|
cpSync(source, target, { recursive: true });
|
|
3141
3217
|
return true;
|
|
3142
3218
|
}
|
|
3143
3219
|
function hydrateContentRoot(projectDir, contentRoot) {
|
|
3144
|
-
if (!
|
|
3145
|
-
const customRoot =
|
|
3146
|
-
const cacheRoot =
|
|
3220
|
+
if (!existsSync23(contentRoot)) return false;
|
|
3221
|
+
const customRoot = join23(projectDir, ".decantr", "custom");
|
|
3222
|
+
const cacheRoot = join23(projectDir, ".decantr", "cache", "@official");
|
|
3147
3223
|
mkdirSync7(customRoot, { recursive: true });
|
|
3148
3224
|
mkdirSync7(cacheRoot, { recursive: true });
|
|
3149
3225
|
let copiedAny = false;
|
|
3150
3226
|
for (const type of CONTENT_TYPES2) {
|
|
3151
|
-
const sourceDir =
|
|
3152
|
-
if (!
|
|
3153
|
-
cpSync(sourceDir,
|
|
3154
|
-
cpSync(sourceDir,
|
|
3227
|
+
const sourceDir = join23(contentRoot, type);
|
|
3228
|
+
if (!existsSync23(sourceDir)) continue;
|
|
3229
|
+
cpSync(sourceDir, join23(customRoot, type), { recursive: true });
|
|
3230
|
+
cpSync(sourceDir, join23(cacheRoot, type), { recursive: true });
|
|
3155
3231
|
copiedAny = true;
|
|
3156
3232
|
}
|
|
3157
3233
|
return copiedAny;
|
|
3158
3234
|
}
|
|
3159
3235
|
function seedOfflineRegistry(projectDir, workspaceRoot) {
|
|
3160
|
-
const projectDecantrRoot =
|
|
3236
|
+
const projectDecantrRoot = join23(projectDir, ".decantr");
|
|
3161
3237
|
mkdirSync7(projectDecantrRoot, { recursive: true });
|
|
3162
|
-
const
|
|
3163
|
-
|
|
3238
|
+
const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve(process.env.DECANTR_CONTENT_DIR) : null;
|
|
3239
|
+
if (configuredContentRoot && hydrateContentRoot(projectDir, configuredContentRoot)) {
|
|
3240
|
+
return { seeded: true, strategy: "configured-content-root" };
|
|
3241
|
+
}
|
|
3242
|
+
const copiedCache = copyIfExists(join23(workspaceRoot, ".decantr", "cache"), join23(projectDecantrRoot, "cache"));
|
|
3243
|
+
const copiedCustom = copyIfExists(join23(workspaceRoot, ".decantr", "custom"), join23(projectDecantrRoot, "custom"));
|
|
3164
3244
|
if (copiedCache || copiedCustom) {
|
|
3165
3245
|
return { seeded: true, strategy: "workspace-cache" };
|
|
3166
3246
|
}
|
|
3167
|
-
const configuredContentRoot = process.env.DECANTR_CONTENT_DIR ? resolve(process.env.DECANTR_CONTENT_DIR) : null;
|
|
3168
3247
|
const siblingContentRoot = resolve(workspaceRoot, "..", "decantr-content");
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
return {
|
|
3172
|
-
seeded: true,
|
|
3173
|
-
strategy: configuredContentRoot && existsSync22(configuredContentRoot) ? "configured-content-root" : "sibling-content-root"
|
|
3174
|
-
};
|
|
3248
|
+
if (hydrateContentRoot(projectDir, siblingContentRoot)) {
|
|
3249
|
+
return { seeded: true, strategy: "sibling-content-root" };
|
|
3175
3250
|
}
|
|
3176
3251
|
return { seeded: false, strategy: null };
|
|
3177
3252
|
}
|
|
3178
3253
|
|
|
3179
|
-
// src/
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
var
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3254
|
+
// src/bootstrap.ts
|
|
3255
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync12 } from "fs";
|
|
3256
|
+
import { basename, join as join24 } from "path";
|
|
3257
|
+
import { resolvePackAdapter } from "@decantr/core";
|
|
3258
|
+
var reactViteBootstrapAdapter = {
|
|
3259
|
+
id: "react-vite",
|
|
3260
|
+
label: "React + Vite starter",
|
|
3261
|
+
writeProjectFiles(projectDir, title, routingMode) {
|
|
3262
|
+
const srcDir = join24(projectDir, "src");
|
|
3263
|
+
const routerImport = routingMode === "hash" ? "HashRouter" : "BrowserRouter";
|
|
3264
|
+
const packageJson = {
|
|
3265
|
+
name: basename(projectDir) || "decantr-app",
|
|
3266
|
+
private: true,
|
|
3267
|
+
version: "0.0.0",
|
|
3268
|
+
type: "module",
|
|
3269
|
+
scripts: {
|
|
3270
|
+
dev: "vite",
|
|
3271
|
+
build: "tsc -b && vite build",
|
|
3272
|
+
preview: "vite preview"
|
|
3273
|
+
},
|
|
3274
|
+
dependencies: {
|
|
3275
|
+
react: "^19.0.0",
|
|
3276
|
+
"react-dom": "^19.0.0",
|
|
3277
|
+
"react-router-dom": "^7.0.0",
|
|
3278
|
+
"@decantr/css": "^1.0.0"
|
|
3279
|
+
},
|
|
3280
|
+
devDependencies: {
|
|
3281
|
+
"@types/react": "^19.0.0",
|
|
3282
|
+
"@types/react-dom": "^19.0.0",
|
|
3283
|
+
"@vitejs/plugin-react": "^4.0.0",
|
|
3284
|
+
typescript: "^5.7.0",
|
|
3285
|
+
vite: "^6.0.0"
|
|
3286
|
+
}
|
|
3287
|
+
};
|
|
3288
|
+
writeFileSync12(join24(projectDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
3289
|
+
const viteConfig = `import { defineConfig } from 'vite';
|
|
3290
|
+
import react from '@vitejs/plugin-react';
|
|
3291
|
+
|
|
3292
|
+
export default defineConfig({
|
|
3293
|
+
plugins: [react()],
|
|
3294
|
+
});
|
|
3190
3295
|
`;
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3296
|
+
writeFileSync12(join24(projectDir, "vite.config.ts"), viteConfig);
|
|
3297
|
+
const tsconfig = {
|
|
3298
|
+
compilerOptions: {
|
|
3299
|
+
target: "ES2020",
|
|
3300
|
+
useDefineForClassFields: true,
|
|
3301
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
3302
|
+
module: "ESNext",
|
|
3303
|
+
skipLibCheck: true,
|
|
3304
|
+
moduleResolution: "bundler",
|
|
3305
|
+
allowImportingTsExtensions: true,
|
|
3306
|
+
isolatedModules: true,
|
|
3307
|
+
moduleDetection: "force",
|
|
3308
|
+
noEmit: true,
|
|
3309
|
+
jsx: "react-jsx",
|
|
3310
|
+
strict: true,
|
|
3311
|
+
noUnusedLocals: true,
|
|
3312
|
+
noUnusedParameters: true,
|
|
3313
|
+
noFallthroughCasesInSwitch: true,
|
|
3314
|
+
noUncheckedSideEffectImports: true
|
|
3315
|
+
},
|
|
3316
|
+
include: ["src"]
|
|
3317
|
+
};
|
|
3318
|
+
writeFileSync12(join24(projectDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
|
|
3319
|
+
const tsconfigApp = {
|
|
3320
|
+
compilerOptions: {
|
|
3321
|
+
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
3322
|
+
target: "ES2020",
|
|
3323
|
+
useDefineForClassFields: true,
|
|
3324
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
3325
|
+
module: "ESNext",
|
|
3326
|
+
skipLibCheck: true,
|
|
3327
|
+
moduleResolution: "bundler",
|
|
3328
|
+
allowImportingTsExtensions: true,
|
|
3329
|
+
isolatedModules: true,
|
|
3330
|
+
moduleDetection: "force",
|
|
3331
|
+
noEmit: true,
|
|
3332
|
+
jsx: "react-jsx",
|
|
3333
|
+
strict: true,
|
|
3334
|
+
noUnusedLocals: true,
|
|
3335
|
+
noUnusedParameters: true,
|
|
3336
|
+
noFallthroughCasesInSwitch: true,
|
|
3337
|
+
noUncheckedSideEffectImports: true
|
|
3338
|
+
},
|
|
3339
|
+
include: ["src"]
|
|
3340
|
+
};
|
|
3341
|
+
writeFileSync12(join24(projectDir, "tsconfig.app.json"), JSON.stringify(tsconfigApp, null, 2) + "\n");
|
|
3342
|
+
const indexHtml = `<!doctype html>
|
|
3343
|
+
<html lang="en">
|
|
3344
|
+
<head>
|
|
3345
|
+
<meta charset="UTF-8" />
|
|
3346
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
3347
|
+
<title>${title}</title>
|
|
3348
|
+
</head>
|
|
3349
|
+
<body>
|
|
3350
|
+
<div id="root"></div>
|
|
3351
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
3352
|
+
</body>
|
|
3353
|
+
</html>
|
|
3354
|
+
`;
|
|
3355
|
+
writeFileSync12(join24(projectDir, "index.html"), indexHtml);
|
|
3356
|
+
mkdirSync8(srcDir, { recursive: true });
|
|
3357
|
+
const mainTsx = `import { StrictMode } from 'react';
|
|
3220
3358
|
import { createRoot } from 'react-dom/client';
|
|
3221
3359
|
import { ${routerImport} } from 'react-router-dom';
|
|
3222
3360
|
import { App } from './App';
|
|
@@ -3232,8 +3370,8 @@ createRoot(document.getElementById('root')!).render(
|
|
|
3232
3370
|
</StrictMode>,
|
|
3233
3371
|
);
|
|
3234
3372
|
`;
|
|
3235
|
-
|
|
3236
|
-
|
|
3373
|
+
writeFileSync12(join24(srcDir, "main.tsx"), mainTsx);
|
|
3374
|
+
const appTsx = `import { css } from '@decantr/css';
|
|
3237
3375
|
import { Routes, Route } from 'react-router-dom';
|
|
3238
3376
|
|
|
3239
3377
|
function WelcomePage() {
|
|
@@ -3267,137 +3405,105 @@ export function App() {
|
|
|
3267
3405
|
);
|
|
3268
3406
|
}
|
|
3269
3407
|
`;
|
|
3270
|
-
|
|
3408
|
+
writeFileSync12(join24(srcDir, "App.tsx"), appTsx);
|
|
3409
|
+
writeFileSync12(join24(srcDir, "vite-env.d.ts"), '/// <reference types="vite/client" />\n');
|
|
3410
|
+
mkdirSync8(join24(srcDir, "styles"), { recursive: true });
|
|
3411
|
+
}
|
|
3412
|
+
};
|
|
3413
|
+
var BOOTSTRAP_ADAPTERS = {
|
|
3414
|
+
"react-vite": reactViteBootstrapAdapter
|
|
3415
|
+
};
|
|
3416
|
+
function resolveBootstrapTarget(target) {
|
|
3417
|
+
const normalizedTarget = (target || "react").toLowerCase();
|
|
3418
|
+
const platformType = "spa";
|
|
3419
|
+
const packAdapter = resolvePackAdapter(normalizedTarget, platformType);
|
|
3420
|
+
return {
|
|
3421
|
+
target: normalizedTarget,
|
|
3422
|
+
platformType,
|
|
3423
|
+
packAdapter,
|
|
3424
|
+
bootstrapAdapterId: BOOTSTRAP_ADAPTERS[packAdapter]?.id ?? null
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
function getBootstrapAdapter(resolution) {
|
|
3428
|
+
if (!resolution.bootstrapAdapterId) {
|
|
3429
|
+
return null;
|
|
3430
|
+
}
|
|
3431
|
+
return BOOTSTRAP_ADAPTERS[resolution.bootstrapAdapterId] ?? null;
|
|
3432
|
+
}
|
|
3433
|
+
function detectRoutingMode(projectDir) {
|
|
3434
|
+
try {
|
|
3435
|
+
const essence = JSON.parse(readFileSync16(join24(projectDir, "decantr.essence.json"), "utf-8"));
|
|
3436
|
+
const routing = essence.meta?.platform?.routing;
|
|
3437
|
+
if (routing === "history" || routing === "pathname") {
|
|
3438
|
+
return routing;
|
|
3439
|
+
}
|
|
3440
|
+
return "hash";
|
|
3441
|
+
} catch {
|
|
3442
|
+
return "hash";
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
// src/commands/new-project.ts
|
|
3447
|
+
var BOLD5 = "\x1B[1m";
|
|
3448
|
+
var DIM12 = "\x1B[2m";
|
|
3449
|
+
var RESET12 = "\x1B[0m";
|
|
3450
|
+
var RED10 = "\x1B[31m";
|
|
3451
|
+
var GREEN12 = "\x1B[32m";
|
|
3452
|
+
var CYAN6 = "\x1B[36m";
|
|
3453
|
+
var YELLOW8 = "\x1B[33m";
|
|
3454
|
+
function heading(text) {
|
|
3455
|
+
return `
|
|
3456
|
+
${BOLD5}${text}${RESET12}
|
|
3457
|
+
`;
|
|
3458
|
+
}
|
|
3459
|
+
function success2(text) {
|
|
3460
|
+
return `${GREEN12}${text}${RESET12}`;
|
|
3271
3461
|
}
|
|
3272
|
-
function
|
|
3273
|
-
return
|
|
3462
|
+
function error2(text) {
|
|
3463
|
+
return `${RED10}${text}${RESET12}`;
|
|
3464
|
+
}
|
|
3465
|
+
function dim2(text) {
|
|
3466
|
+
return `${DIM12}${text}${RESET12}`;
|
|
3467
|
+
}
|
|
3468
|
+
function cyan2(text) {
|
|
3469
|
+
return `${CYAN6}${text}${RESET12}`;
|
|
3274
3470
|
}
|
|
3275
3471
|
async function cmdNewProject(projectName, options) {
|
|
3276
3472
|
const workspaceRoot = process.cwd();
|
|
3277
3473
|
const projectDir = resolve2(workspaceRoot, projectName);
|
|
3474
|
+
const bootstrapTarget = resolveBootstrapTarget(options.target);
|
|
3475
|
+
const bootstrapAdapter = getBootstrapAdapter(bootstrapTarget);
|
|
3476
|
+
const hasRunnableBootstrap = Boolean(bootstrapAdapter);
|
|
3278
3477
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(projectName)) {
|
|
3279
3478
|
console.error(error2("Invalid project name. Use alphanumeric characters, hyphens, dots, or underscores."));
|
|
3280
3479
|
process.exitCode = 1;
|
|
3281
3480
|
return;
|
|
3282
3481
|
}
|
|
3283
|
-
if (
|
|
3482
|
+
if (existsSync24(projectDir)) {
|
|
3284
3483
|
console.error(error2(`Directory "${projectName}" already exists.`));
|
|
3285
3484
|
process.exitCode = 1;
|
|
3286
3485
|
return;
|
|
3287
3486
|
}
|
|
3288
3487
|
console.log(heading(`Creating ${projectName}...`));
|
|
3289
|
-
|
|
3488
|
+
mkdirSync9(projectDir, { recursive: true });
|
|
3290
3489
|
console.log(dim2(` Created ${projectName}/`));
|
|
3291
|
-
const packageJson = {
|
|
3292
|
-
name: projectName,
|
|
3293
|
-
private: true,
|
|
3294
|
-
version: "0.0.0",
|
|
3295
|
-
type: "module",
|
|
3296
|
-
scripts: {
|
|
3297
|
-
dev: "vite",
|
|
3298
|
-
build: "tsc -b && vite build",
|
|
3299
|
-
preview: "vite preview"
|
|
3300
|
-
},
|
|
3301
|
-
dependencies: {
|
|
3302
|
-
"react": "^19.0.0",
|
|
3303
|
-
"react-dom": "^19.0.0",
|
|
3304
|
-
"react-router-dom": "^7.0.0",
|
|
3305
|
-
"@decantr/css": "^1.0.0"
|
|
3306
|
-
},
|
|
3307
|
-
devDependencies: {
|
|
3308
|
-
"@types/react": "^19.0.0",
|
|
3309
|
-
"@types/react-dom": "^19.0.0",
|
|
3310
|
-
"@vitejs/plugin-react": "^4.0.0",
|
|
3311
|
-
"typescript": "^5.7.0",
|
|
3312
|
-
"vite": "^6.0.0"
|
|
3313
|
-
}
|
|
3314
|
-
};
|
|
3315
|
-
writeFileSync12(join23(projectDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
3316
|
-
console.log(dim2(" Created package.json"));
|
|
3317
|
-
const viteConfig = `import { defineConfig } from 'vite';
|
|
3318
|
-
import react from '@vitejs/plugin-react';
|
|
3319
|
-
|
|
3320
|
-
export default defineConfig({
|
|
3321
|
-
plugins: [react()],
|
|
3322
|
-
});
|
|
3323
|
-
`;
|
|
3324
|
-
writeFileSync12(join23(projectDir, "vite.config.ts"), viteConfig);
|
|
3325
|
-
console.log(dim2(" Created vite.config.ts"));
|
|
3326
|
-
const tsconfig = {
|
|
3327
|
-
compilerOptions: {
|
|
3328
|
-
target: "ES2020",
|
|
3329
|
-
useDefineForClassFields: true,
|
|
3330
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
3331
|
-
module: "ESNext",
|
|
3332
|
-
skipLibCheck: true,
|
|
3333
|
-
moduleResolution: "bundler",
|
|
3334
|
-
allowImportingTsExtensions: true,
|
|
3335
|
-
isolatedModules: true,
|
|
3336
|
-
moduleDetection: "force",
|
|
3337
|
-
noEmit: true,
|
|
3338
|
-
jsx: "react-jsx",
|
|
3339
|
-
strict: true,
|
|
3340
|
-
noUnusedLocals: true,
|
|
3341
|
-
noUnusedParameters: true,
|
|
3342
|
-
noFallthroughCasesInSwitch: true,
|
|
3343
|
-
noUncheckedSideEffectImports: true
|
|
3344
|
-
},
|
|
3345
|
-
include: ["src"]
|
|
3346
|
-
};
|
|
3347
|
-
writeFileSync12(join23(projectDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n");
|
|
3348
|
-
const tsconfigApp = {
|
|
3349
|
-
compilerOptions: {
|
|
3350
|
-
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
3351
|
-
target: "ES2020",
|
|
3352
|
-
useDefineForClassFields: true,
|
|
3353
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
3354
|
-
module: "ESNext",
|
|
3355
|
-
skipLibCheck: true,
|
|
3356
|
-
moduleResolution: "bundler",
|
|
3357
|
-
allowImportingTsExtensions: true,
|
|
3358
|
-
isolatedModules: true,
|
|
3359
|
-
moduleDetection: "force",
|
|
3360
|
-
noEmit: true,
|
|
3361
|
-
jsx: "react-jsx",
|
|
3362
|
-
strict: true,
|
|
3363
|
-
noUnusedLocals: true,
|
|
3364
|
-
noUnusedParameters: true,
|
|
3365
|
-
noFallthroughCasesInSwitch: true,
|
|
3366
|
-
noUncheckedSideEffectImports: true
|
|
3367
|
-
},
|
|
3368
|
-
include: ["src"]
|
|
3369
|
-
};
|
|
3370
|
-
writeFileSync12(join23(projectDir, "tsconfig.app.json"), JSON.stringify(tsconfigApp, null, 2) + "\n");
|
|
3371
|
-
console.log(dim2(" Created tsconfig.json"));
|
|
3372
3490
|
const title = projectName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
<body>
|
|
3381
|
-
<div id="root"></div>
|
|
3382
|
-
<script type="module" src="/src/main.tsx"></script>
|
|
3383
|
-
</body>
|
|
3384
|
-
</html>
|
|
3385
|
-
`;
|
|
3386
|
-
writeFileSync12(join23(projectDir, "index.html"), indexHtml);
|
|
3387
|
-
console.log(dim2(" Created index.html"));
|
|
3388
|
-
const srcDir = join23(projectDir, "src");
|
|
3389
|
-
mkdirSync8(srcDir, { recursive: true });
|
|
3390
|
-
writeStarterRuntimeFiles(projectDir, title, getTargetRoutingMode(options.target));
|
|
3391
|
-
writeFileSync12(join23(srcDir, "vite-env.d.ts"), '/// <reference types="vite/client" />\n');
|
|
3392
|
-
mkdirSync8(join23(srcDir, "styles"), { recursive: true });
|
|
3393
|
-
console.log(dim2(" Created src/"));
|
|
3394
|
-
console.log(heading("Installing dependencies..."));
|
|
3491
|
+
if (bootstrapAdapter) {
|
|
3492
|
+
bootstrapAdapter.writeProjectFiles(projectDir, title, "hash");
|
|
3493
|
+
console.log(dim2(` Bootstrapped ${bootstrapAdapter.label}`));
|
|
3494
|
+
} else {
|
|
3495
|
+
console.log(`${YELLOW8} No greenfield bootstrap adapter is available yet for target "${bootstrapTarget.target}" (${bootstrapTarget.packAdapter}).${RESET12}`);
|
|
3496
|
+
console.log(dim2(" Continuing with a contract-only Decantr workspace so the command stays target-honest instead of writing the wrong runtime."));
|
|
3497
|
+
}
|
|
3395
3498
|
const packageManager = detectPackageManager();
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3499
|
+
if (hasRunnableBootstrap) {
|
|
3500
|
+
console.log(heading("Installing dependencies..."));
|
|
3501
|
+
try {
|
|
3502
|
+
execSync(`${packageManager} install`, { cwd: projectDir, stdio: "inherit" });
|
|
3503
|
+
} catch {
|
|
3504
|
+
console.log(`
|
|
3400
3505
|
${YELLOW8}Dependency install failed. Run \`${packageManager} install\` manually.${RESET12}`);
|
|
3506
|
+
}
|
|
3401
3507
|
}
|
|
3402
3508
|
const requiresOfflineContent = Boolean(options.offline && (options.blueprint || options.archetype));
|
|
3403
3509
|
const seeded = options.offline ? seedOfflineRegistry(projectDir, workspaceRoot) : { seeded: false, strategy: null };
|
|
@@ -3429,10 +3535,12 @@ ${YELLOW8}Dependency install failed. Run \`${packageManager} install\` manually.
|
|
|
3429
3535
|
if (options.registry) initFlags.push(`--registry=${options.registry}`);
|
|
3430
3536
|
try {
|
|
3431
3537
|
const bundledCliEntrypoint = fileURLToPath(new URL("./bin.js", import.meta.url));
|
|
3432
|
-
const cliEntrypoint =
|
|
3538
|
+
const cliEntrypoint = existsSync24(bundledCliEntrypoint) ? bundledCliEntrypoint : process.argv[1] && existsSync24(process.argv[1]) ? process.argv[1] : null;
|
|
3433
3539
|
const cliPath = cliEntrypoint ? `"${process.execPath}" "${cliEntrypoint}"` : "npx decantr";
|
|
3434
3540
|
execSync(`${cliPath} init ${initFlags.join(" ")}`, { cwd: projectDir, stdio: "inherit" });
|
|
3435
|
-
|
|
3541
|
+
if (bootstrapAdapter) {
|
|
3542
|
+
bootstrapAdapter.writeProjectFiles(projectDir, title, detectRoutingMode(projectDir));
|
|
3543
|
+
}
|
|
3436
3544
|
} catch {
|
|
3437
3545
|
console.log(`
|
|
3438
3546
|
${YELLOW8}Decantr init encountered issues. Run \`decantr init\` manually inside ${projectName}/.${RESET12}`);
|
|
@@ -3441,17 +3549,21 @@ ${YELLOW8}Decantr init encountered issues. Run \`decantr init\` manually inside
|
|
|
3441
3549
|
\u2713 Project "${projectName}" created!
|
|
3442
3550
|
`));
|
|
3443
3551
|
console.log(` ${cyan2("cd " + projectName)}`);
|
|
3444
|
-
|
|
3552
|
+
if (bootstrapAdapter) {
|
|
3553
|
+
console.log(` ${cyan2(packageManager + " run dev")}`);
|
|
3554
|
+
} else {
|
|
3555
|
+
console.log(dim2(` Contract-only mode for target ${bootstrapTarget.target}. Bring your own runtime, or rerun ${cyan2(`decantr new ${projectName} --target=react`)} for the current starter adapter.`));
|
|
3556
|
+
}
|
|
3445
3557
|
console.log("");
|
|
3446
3558
|
}
|
|
3447
3559
|
function detectPackageManager() {
|
|
3448
|
-
if (
|
|
3560
|
+
if (existsSync24(join25(process.cwd(), "pnpm-lock.yaml")) || existsSync24(join25(process.cwd(), "pnpm-workspace.yaml"))) {
|
|
3449
3561
|
return "pnpm";
|
|
3450
3562
|
}
|
|
3451
|
-
if (
|
|
3563
|
+
if (existsSync24(join25(process.cwd(), "yarn.lock"))) {
|
|
3452
3564
|
return "yarn";
|
|
3453
3565
|
}
|
|
3454
|
-
if (
|
|
3566
|
+
if (existsSync24(join25(process.cwd(), "bun.lockb")) || existsSync24(join25(process.cwd(), "bun.lock"))) {
|
|
3455
3567
|
return "bun";
|
|
3456
3568
|
}
|
|
3457
3569
|
return "npm";
|
|
@@ -3572,6 +3684,12 @@ function generateCuratedPrompt(ctx) {
|
|
|
3572
3684
|
lines.push("- Start with the shell layouts and route structure first, then build section pages route by route.");
|
|
3573
3685
|
lines.push("- Import src/styles/global.css, src/styles/tokens.css, and src/styles/treatments.css.");
|
|
3574
3686
|
lines.push("- Use the existing Decantr tokens, treatments, and decorators instead of inventing a new visual system.");
|
|
3687
|
+
lines.push("- If package.json, app entry files, or router/runtime files are absent, create them explicitly for the declared target instead of assuming a hidden starter already exists in the workspace.");
|
|
3688
|
+
lines.push("- Do not use inline visual style values or component-scoped <style> tags as the primary styling path. Colors, spacing, borders, shadows, gradients, and transitions should come from atoms, treatments, decorators, or CSS variables. Inline styles are only acceptable for truly dynamic geometry that cannot be expressed through the contract.");
|
|
3689
|
+
lines.push("- Let shells own spacing, centering, and scroll containers. Pages should not duplicate shell responsibilities with extra full-height wrappers, max-width wrappers, or page-local padding unless the route contract explicitly requires it.");
|
|
3690
|
+
lines.push("- If command_palette or hotkeys are declared in the generated context, implement them as real features. Do not merely acknowledge them in copy or comments.");
|
|
3691
|
+
lines.push("- Treat declared hotkeys as interaction bindings by default, not visible navigation label text, unless the shell or route contract explicitly calls for shown shortcut hints.");
|
|
3692
|
+
lines.push("- If a required decorator class is referenced in the contract but missing from generated CSS, report the contract gap instead of inventing a parallel visual system.");
|
|
3575
3693
|
lines.push("- Do not modify generated context files unless the task is explicitly to regenerate or refresh Decantr context.");
|
|
3576
3694
|
lines.push("");
|
|
3577
3695
|
lines.push("Execution flow:");
|
|
@@ -3606,18 +3724,18 @@ function extractHostedAssetPaths(indexHtml) {
|
|
|
3606
3724
|
return [...assetPaths];
|
|
3607
3725
|
}
|
|
3608
3726
|
function readHostedDistSnapshot(distPath) {
|
|
3609
|
-
const resolvedDistPath = distPath ? resolveUserPath(distPath) :
|
|
3610
|
-
const indexPath =
|
|
3611
|
-
if (!
|
|
3727
|
+
const resolvedDistPath = distPath ? resolveUserPath(distPath) : join26(process.cwd(), "dist");
|
|
3728
|
+
const indexPath = join26(resolvedDistPath, "index.html");
|
|
3729
|
+
if (!existsSync25(indexPath)) {
|
|
3612
3730
|
return void 0;
|
|
3613
3731
|
}
|
|
3614
|
-
const indexHtml =
|
|
3732
|
+
const indexHtml = readFileSync17(indexPath, "utf-8");
|
|
3615
3733
|
const assetPaths = extractHostedAssetPaths(indexHtml);
|
|
3616
3734
|
const assets = {};
|
|
3617
3735
|
for (const assetPath of assetPaths) {
|
|
3618
|
-
const assetFilePath =
|
|
3619
|
-
if (
|
|
3620
|
-
assets[assetPath] =
|
|
3736
|
+
const assetFilePath = join26(resolvedDistPath, assetPath.replace(/^[/\\]+/, ""));
|
|
3737
|
+
if (existsSync25(assetFilePath)) {
|
|
3738
|
+
assets[assetPath] = readFileSync17(assetFilePath, "utf-8");
|
|
3621
3739
|
}
|
|
3622
3740
|
}
|
|
3623
3741
|
return {
|
|
@@ -3632,24 +3750,24 @@ function isHostedSourceSnapshotFile(path) {
|
|
|
3632
3750
|
function readHostedSourceSnapshot(sourcePath) {
|
|
3633
3751
|
if (!sourcePath) return void 0;
|
|
3634
3752
|
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
3635
|
-
if (!
|
|
3753
|
+
if (!existsSync25(resolvedSourcePath)) {
|
|
3636
3754
|
return void 0;
|
|
3637
3755
|
}
|
|
3638
3756
|
const files = {};
|
|
3639
3757
|
const ignoredDirNames = /* @__PURE__ */ new Set(["node_modules", ".git", ".decantr", "dist", "build", "coverage"]);
|
|
3640
|
-
const rootPrefix =
|
|
3758
|
+
const rootPrefix = basename2(resolvedSourcePath);
|
|
3641
3759
|
const walk = (absoluteDir, relativeDir) => {
|
|
3642
3760
|
for (const entry of readdirSync6(absoluteDir, { withFileTypes: true })) {
|
|
3643
3761
|
if (ignoredDirNames.has(entry.name)) continue;
|
|
3644
|
-
const absolutePath =
|
|
3645
|
-
const relativePath =
|
|
3762
|
+
const absolutePath = join26(absoluteDir, entry.name);
|
|
3763
|
+
const relativePath = join26(relativeDir, entry.name).replace(/\\/g, "/");
|
|
3646
3764
|
if (entry.isDirectory()) {
|
|
3647
3765
|
walk(absolutePath, relativePath);
|
|
3648
3766
|
continue;
|
|
3649
3767
|
}
|
|
3650
3768
|
if (!entry.isFile()) continue;
|
|
3651
3769
|
if (!isHostedSourceSnapshotFile(relativePath)) continue;
|
|
3652
|
-
files[relativePath] =
|
|
3770
|
+
files[relativePath] = readFileSync17(absolutePath, "utf-8");
|
|
3653
3771
|
}
|
|
3654
3772
|
};
|
|
3655
3773
|
walk(resolvedSourcePath, rootPrefix);
|
|
@@ -3766,19 +3884,19 @@ async function printRegistryIntelligenceSummary(namespace, jsonOutput = false) {
|
|
|
3766
3884
|
}
|
|
3767
3885
|
async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3768
3886
|
const client = getPublicAPIClient();
|
|
3769
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
3770
|
-
if (!
|
|
3887
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join26(process.cwd(), "decantr.essence.json");
|
|
3888
|
+
if (!existsSync25(resolvedPath)) {
|
|
3771
3889
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3772
3890
|
}
|
|
3773
|
-
const essence = JSON.parse(
|
|
3891
|
+
const essence = JSON.parse(readFileSync17(resolvedPath, "utf-8"));
|
|
3774
3892
|
const bundle = await client.compileExecutionPacks(
|
|
3775
3893
|
essence,
|
|
3776
3894
|
namespace ? { namespace } : void 0
|
|
3777
3895
|
);
|
|
3778
3896
|
let writtenContextPaths = [];
|
|
3779
3897
|
if (writeContext) {
|
|
3780
|
-
const contextDir =
|
|
3781
|
-
|
|
3898
|
+
const contextDir = join26(process.cwd(), ".decantr", "context");
|
|
3899
|
+
mkdirSync10(contextDir, { recursive: true });
|
|
3782
3900
|
const written = writeExecutionPackBundleArtifacts(
|
|
3783
3901
|
contextDir,
|
|
3784
3902
|
bundle
|
|
@@ -3801,7 +3919,7 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
|
|
|
3801
3919
|
console.log(` Sections: ${typedBundle.sections.length}`);
|
|
3802
3920
|
console.log(` Mutations: ${typedBundle.mutations.length}`);
|
|
3803
3921
|
if (writeContext) {
|
|
3804
|
-
console.log(` Context bundle: ${
|
|
3922
|
+
console.log(` Context bundle: ${join26(process.cwd(), ".decantr", "context")}`);
|
|
3805
3923
|
console.log(` Files written: ${writtenContextPaths.length}`);
|
|
3806
3924
|
}
|
|
3807
3925
|
console.log("");
|
|
@@ -3813,14 +3931,14 @@ async function printHostedExecutionPackBundle(essencePath, namespace, jsonOutput
|
|
|
3813
3931
|
}
|
|
3814
3932
|
async function printHostedSelectedExecutionPack(packType, id, essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3815
3933
|
const client = getPublicAPIClient();
|
|
3816
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
3817
|
-
if (!
|
|
3934
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join26(process.cwd(), "decantr.essence.json");
|
|
3935
|
+
if (!existsSync25(resolvedPath)) {
|
|
3818
3936
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3819
3937
|
}
|
|
3820
3938
|
if ((packType === "section" || packType === "page" || packType === "mutation") && !id) {
|
|
3821
3939
|
throw new Error(`Pack type "${packType}" requires an id.`);
|
|
3822
3940
|
}
|
|
3823
|
-
const essence = JSON.parse(
|
|
3941
|
+
const essence = JSON.parse(readFileSync17(resolvedPath, "utf-8"));
|
|
3824
3942
|
const selected = await client.selectExecutionPack(
|
|
3825
3943
|
{
|
|
3826
3944
|
essence,
|
|
@@ -3831,14 +3949,14 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
|
|
|
3831
3949
|
);
|
|
3832
3950
|
let writtenContextDir = null;
|
|
3833
3951
|
if (writeContext) {
|
|
3834
|
-
const contextDir =
|
|
3835
|
-
|
|
3836
|
-
writeFileSync13(
|
|
3952
|
+
const contextDir = join26(process.cwd(), ".decantr", "context");
|
|
3953
|
+
mkdirSync10(contextDir, { recursive: true });
|
|
3954
|
+
writeFileSync13(join26(contextDir, "pack-manifest.json"), JSON.stringify(selected.manifest, null, 2) + "\n");
|
|
3837
3955
|
const manifestEntry = selected.selector.packType === "scaffold" ? selected.manifest.scaffold : selected.selector.packType === "review" ? selected.manifest.review : selected.selector.packType === "section" ? selected.manifest.sections.find((entry) => entry.id === selected.selector.id) : selected.selector.packType === "page" ? selected.manifest.pages.find((entry) => entry.id === selected.selector.id) : selected.manifest.mutations.find((entry) => entry.id === selected.selector.id);
|
|
3838
3956
|
const markdownFile = manifestEntry?.markdown ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.md`;
|
|
3839
3957
|
const jsonFile = manifestEntry?.json ?? `${selected.selector.packType}${selected.selector.id ? `-${selected.selector.id}` : ""}-pack.json`;
|
|
3840
|
-
writeFileSync13(
|
|
3841
|
-
writeFileSync13(
|
|
3958
|
+
writeFileSync13(join26(contextDir, markdownFile), selected.pack.renderedMarkdown);
|
|
3959
|
+
writeFileSync13(join26(contextDir, jsonFile), JSON.stringify(selected.pack, null, 2) + "\n");
|
|
3842
3960
|
writtenContextDir = contextDir;
|
|
3843
3961
|
}
|
|
3844
3962
|
if (jsonOutput) {
|
|
@@ -3863,20 +3981,20 @@ async function printHostedSelectedExecutionPack(packType, id, essencePath, names
|
|
|
3863
3981
|
}
|
|
3864
3982
|
async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutput = false, writeContext = false) {
|
|
3865
3983
|
const client = getPublicAPIClient();
|
|
3866
|
-
const resolvedPath = essencePath ? resolveUserPath(essencePath) :
|
|
3867
|
-
if (!
|
|
3984
|
+
const resolvedPath = essencePath ? resolveUserPath(essencePath) : join26(process.cwd(), "decantr.essence.json");
|
|
3985
|
+
if (!existsSync25(resolvedPath)) {
|
|
3868
3986
|
throw new Error(`Essence file not found at ${resolvedPath}`);
|
|
3869
3987
|
}
|
|
3870
|
-
const essence = JSON.parse(
|
|
3988
|
+
const essence = JSON.parse(readFileSync17(resolvedPath, "utf-8"));
|
|
3871
3989
|
const manifest = await client.getExecutionPackManifest(
|
|
3872
3990
|
essence,
|
|
3873
3991
|
namespace ? { namespace } : void 0
|
|
3874
3992
|
);
|
|
3875
3993
|
let writtenContextDir = null;
|
|
3876
3994
|
if (writeContext) {
|
|
3877
|
-
const contextDir =
|
|
3878
|
-
|
|
3879
|
-
writeFileSync13(
|
|
3995
|
+
const contextDir = join26(process.cwd(), ".decantr", "context");
|
|
3996
|
+
mkdirSync10(contextDir, { recursive: true });
|
|
3997
|
+
writeFileSync13(join26(contextDir, "pack-manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
3880
3998
|
writtenContextDir = contextDir;
|
|
3881
3999
|
}
|
|
3882
4000
|
if (jsonOutput) {
|
|
@@ -3897,14 +4015,14 @@ async function printHostedExecutionPackManifest(essencePath, namespace, jsonOutp
|
|
|
3897
4015
|
}
|
|
3898
4016
|
}
|
|
3899
4017
|
async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@official") {
|
|
3900
|
-
const contextDir =
|
|
3901
|
-
const reviewPackPath =
|
|
3902
|
-
const manifestPath =
|
|
3903
|
-
if (
|
|
4018
|
+
const contextDir = join26(projectRoot, ".decantr", "context");
|
|
4019
|
+
const reviewPackPath = join26(contextDir, "review-pack.json");
|
|
4020
|
+
const manifestPath = join26(contextDir, "pack-manifest.json");
|
|
4021
|
+
if (existsSync25(reviewPackPath) && existsSync25(manifestPath)) {
|
|
3904
4022
|
return { attempted: false, hydrated: false };
|
|
3905
4023
|
}
|
|
3906
|
-
const essencePath =
|
|
3907
|
-
if (!
|
|
4024
|
+
const essencePath = join26(projectRoot, "decantr.essence.json");
|
|
4025
|
+
if (!existsSync25(essencePath)) {
|
|
3908
4026
|
return { attempted: false, hydrated: false };
|
|
3909
4027
|
}
|
|
3910
4028
|
const reviewHydration = await hydrateHostedReviewPackIfMissing(projectRoot, namespace);
|
|
@@ -3913,9 +4031,9 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
|
|
|
3913
4031
|
}
|
|
3914
4032
|
try {
|
|
3915
4033
|
const client = getPublicAPIClient();
|
|
3916
|
-
const essence = JSON.parse(
|
|
4034
|
+
const essence = JSON.parse(readFileSync17(essencePath, "utf-8"));
|
|
3917
4035
|
const bundle = await client.compileExecutionPacks(essence, { namespace });
|
|
3918
|
-
|
|
4036
|
+
mkdirSync10(contextDir, { recursive: true });
|
|
3919
4037
|
writeExecutionPackBundleArtifacts(
|
|
3920
4038
|
contextDir,
|
|
3921
4039
|
bundle
|
|
@@ -3926,19 +4044,19 @@ async function hydrateHostedExecutionPacksIfMissing(projectRoot, namespace = "@o
|
|
|
3926
4044
|
}
|
|
3927
4045
|
}
|
|
3928
4046
|
async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@official") {
|
|
3929
|
-
const contextDir =
|
|
3930
|
-
const reviewPackPath =
|
|
3931
|
-
const manifestPath =
|
|
3932
|
-
if (
|
|
4047
|
+
const contextDir = join26(projectRoot, ".decantr", "context");
|
|
4048
|
+
const reviewPackPath = join26(contextDir, "review-pack.json");
|
|
4049
|
+
const manifestPath = join26(contextDir, "pack-manifest.json");
|
|
4050
|
+
if (existsSync25(reviewPackPath) && existsSync25(manifestPath)) {
|
|
3933
4051
|
return { attempted: false, hydrated: false };
|
|
3934
4052
|
}
|
|
3935
|
-
const essencePath =
|
|
3936
|
-
if (!
|
|
4053
|
+
const essencePath = join26(projectRoot, "decantr.essence.json");
|
|
4054
|
+
if (!existsSync25(essencePath)) {
|
|
3937
4055
|
return { attempted: false, hydrated: false };
|
|
3938
4056
|
}
|
|
3939
4057
|
try {
|
|
3940
4058
|
const client = getPublicAPIClient();
|
|
3941
|
-
const essence = JSON.parse(
|
|
4059
|
+
const essence = JSON.parse(readFileSync17(essencePath, "utf-8"));
|
|
3942
4060
|
const selected = await client.selectExecutionPack(
|
|
3943
4061
|
{
|
|
3944
4062
|
essence,
|
|
@@ -3946,10 +4064,10 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
|
|
|
3946
4064
|
},
|
|
3947
4065
|
{ namespace }
|
|
3948
4066
|
);
|
|
3949
|
-
|
|
3950
|
-
writeFileSync13(
|
|
3951
|
-
writeFileSync13(
|
|
3952
|
-
if (!
|
|
4067
|
+
mkdirSync10(contextDir, { recursive: true });
|
|
4068
|
+
writeFileSync13(join26(contextDir, "review-pack.md"), selected.pack.renderedMarkdown);
|
|
4069
|
+
writeFileSync13(join26(contextDir, "review-pack.json"), JSON.stringify(selected.pack, null, 2) + "\n");
|
|
4070
|
+
if (!existsSync25(manifestPath)) {
|
|
3953
4071
|
writeFileSync13(manifestPath, JSON.stringify(selected.manifest, null, 2) + "\n");
|
|
3954
4072
|
}
|
|
3955
4073
|
return { attempted: true, hydrated: true, scope: "review" };
|
|
@@ -3960,17 +4078,17 @@ async function hydrateHostedReviewPackIfMissing(projectRoot, namespace = "@offic
|
|
|
3960
4078
|
async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false, essencePath, treatmentsPath) {
|
|
3961
4079
|
const client = getPublicAPIClient();
|
|
3962
4080
|
const resolvedSourcePath = resolveUserPath(sourcePath);
|
|
3963
|
-
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) :
|
|
3964
|
-
const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) :
|
|
3965
|
-
if (!
|
|
4081
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join26(process.cwd(), "decantr.essence.json");
|
|
4082
|
+
const resolvedTreatmentsPath = treatmentsPath ? resolveUserPath(treatmentsPath) : join26(process.cwd(), "src", "styles", "treatments.css");
|
|
4083
|
+
if (!existsSync25(resolvedSourcePath)) {
|
|
3966
4084
|
throw new Error(`Source file not found at ${resolvedSourcePath}`);
|
|
3967
4085
|
}
|
|
3968
|
-
if (!
|
|
4086
|
+
if (!existsSync25(resolvedEssencePath)) {
|
|
3969
4087
|
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
3970
4088
|
}
|
|
3971
|
-
const code =
|
|
3972
|
-
const essence = JSON.parse(
|
|
3973
|
-
const treatmentsCss =
|
|
4089
|
+
const code = readFileSync17(resolvedSourcePath, "utf-8");
|
|
4090
|
+
const essence = JSON.parse(readFileSync17(resolvedEssencePath, "utf-8"));
|
|
4091
|
+
const treatmentsCss = existsSync25(resolvedTreatmentsPath) ? readFileSync17(resolvedTreatmentsPath, "utf-8") : void 0;
|
|
3974
4092
|
const report = await client.critiqueFile(
|
|
3975
4093
|
{
|
|
3976
4094
|
essence,
|
|
@@ -3994,11 +4112,11 @@ async function printHostedFileCritique(sourcePath, namespace, jsonOutput = false
|
|
|
3994
4112
|
}
|
|
3995
4113
|
async function printHostedProjectAudit(namespace, jsonOutput = false, essencePath, distPath, sourcesPath) {
|
|
3996
4114
|
const client = getPublicAPIClient();
|
|
3997
|
-
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) :
|
|
3998
|
-
if (!
|
|
4115
|
+
const resolvedEssencePath = essencePath ? resolveUserPath(essencePath) : join26(process.cwd(), "decantr.essence.json");
|
|
4116
|
+
if (!existsSync25(resolvedEssencePath)) {
|
|
3999
4117
|
throw new Error(`Essence file not found at ${resolvedEssencePath}`);
|
|
4000
4118
|
}
|
|
4001
|
-
const essence = JSON.parse(
|
|
4119
|
+
const essence = JSON.parse(readFileSync17(resolvedEssencePath, "utf-8"));
|
|
4002
4120
|
const dist = readHostedDistSnapshot(distPath);
|
|
4003
4121
|
const sources = readHostedSourceSnapshot(sourcesPath);
|
|
4004
4122
|
const report = await client.auditProject(
|
|
@@ -4015,7 +4133,7 @@ async function printHostedProjectAudit(namespace, jsonOutput = false, essencePat
|
|
|
4015
4133
|
}
|
|
4016
4134
|
console.log(heading2("Hosted Project Audit"));
|
|
4017
4135
|
console.log(` Essence: ${resolvedEssencePath}`);
|
|
4018
|
-
console.log(` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) :
|
|
4136
|
+
console.log(` Dist snapshot: ${dist ? distPath ? resolveUserPath(distPath) : join26(process.cwd(), "dist") : "none"}`);
|
|
4019
4137
|
console.log(` Source snapshot: ${sources && sourcesPath ? resolveUserPath(sourcesPath) : "none"}`);
|
|
4020
4138
|
printProjectAuditReport(report);
|
|
4021
4139
|
}
|
|
@@ -4093,7 +4211,7 @@ async function cmdGet(type, id) {
|
|
|
4093
4211
|
}
|
|
4094
4212
|
const apiType = CONTENT_TYPE_TO_API_CONTENT_TYPE3[type];
|
|
4095
4213
|
const registryClient = new RegistryClient({
|
|
4096
|
-
cacheDir:
|
|
4214
|
+
cacheDir: join26(process.cwd(), ".decantr", "cache")
|
|
4097
4215
|
});
|
|
4098
4216
|
const result = await registryClient.fetchContentItem(apiType, id);
|
|
4099
4217
|
if (result) {
|
|
@@ -4102,16 +4220,16 @@ async function cmdGet(type, id) {
|
|
|
4102
4220
|
}
|
|
4103
4221
|
const currentDir = dirname2(fileURLToPath2(import.meta.url));
|
|
4104
4222
|
const bundledCandidates = [
|
|
4105
|
-
|
|
4223
|
+
join26(currentDir, "bundled", apiType, `${id}.json`),
|
|
4106
4224
|
// Running from src/
|
|
4107
|
-
|
|
4225
|
+
join26(currentDir, "..", "src", "bundled", apiType, `${id}.json`),
|
|
4108
4226
|
// Running from dist/
|
|
4109
|
-
|
|
4227
|
+
join26(currentDir, "..", "bundled", apiType, `${id}.json`)
|
|
4110
4228
|
// Alternative dist layout
|
|
4111
4229
|
];
|
|
4112
|
-
const bundledPath = bundledCandidates.find((p) =>
|
|
4230
|
+
const bundledPath = bundledCandidates.find((p) => existsSync25(p)) || null;
|
|
4113
4231
|
if (bundledPath) {
|
|
4114
|
-
const data = JSON.parse(
|
|
4232
|
+
const data = JSON.parse(readFileSync17(bundledPath, "utf-8"));
|
|
4115
4233
|
console.log(JSON.stringify(data, null, 2));
|
|
4116
4234
|
return;
|
|
4117
4235
|
}
|
|
@@ -4120,10 +4238,10 @@ async function cmdGet(type, id) {
|
|
|
4120
4238
|
return;
|
|
4121
4239
|
}
|
|
4122
4240
|
async function cmdValidate(path) {
|
|
4123
|
-
const essencePath = path ||
|
|
4241
|
+
const essencePath = path || join26(process.cwd(), "decantr.essence.json");
|
|
4124
4242
|
let raw;
|
|
4125
4243
|
try {
|
|
4126
|
-
raw =
|
|
4244
|
+
raw = readFileSync17(essencePath, "utf-8");
|
|
4127
4245
|
} catch {
|
|
4128
4246
|
console.error(error3(`Could not read ${essencePath}`));
|
|
4129
4247
|
process.exitCode = 1;
|
|
@@ -4177,7 +4295,7 @@ async function cmdList(type, sort, recommended, intelligenceSource) {
|
|
|
4177
4295
|
return;
|
|
4178
4296
|
}
|
|
4179
4297
|
const registryClient = new RegistryClient({
|
|
4180
|
-
cacheDir:
|
|
4298
|
+
cacheDir: join26(process.cwd(), ".decantr", "cache")
|
|
4181
4299
|
});
|
|
4182
4300
|
const result = await registryClient.fetchContentList(
|
|
4183
4301
|
type,
|
|
@@ -4227,6 +4345,11 @@ async function cmdInit(args) {
|
|
|
4227
4345
|
const projectRoot = process.cwd();
|
|
4228
4346
|
console.log(heading2("Decantr Project Setup"));
|
|
4229
4347
|
const detected = detectProject(projectRoot);
|
|
4348
|
+
const workflowSeed = readBrownfieldInitSeed(projectRoot);
|
|
4349
|
+
const brownfieldAttach = Boolean(workflowSeed) || hasExistingProjectFootprint(detected);
|
|
4350
|
+
if (workflowSeed) {
|
|
4351
|
+
console.log(dim3(" Found .decantr/init-seed.json brownfield guidance."));
|
|
4352
|
+
}
|
|
4230
4353
|
if (detected.existingEssence && !args.existing) {
|
|
4231
4354
|
console.log(`${YELLOW9}Warning: decantr.essence.json already exists.${RESET13}`);
|
|
4232
4355
|
const overwrite = await confirm("Overwrite existing configuration?", false);
|
|
@@ -4251,7 +4374,7 @@ async function cmdInit(args) {
|
|
|
4251
4374
|
}
|
|
4252
4375
|
}
|
|
4253
4376
|
const registryClient = new RegistryClient({
|
|
4254
|
-
cacheDir:
|
|
4377
|
+
cacheDir: join26(projectRoot, ".decantr", "cache"),
|
|
4255
4378
|
apiUrl: args.registry,
|
|
4256
4379
|
offline: args.offline
|
|
4257
4380
|
});
|
|
@@ -4265,6 +4388,7 @@ async function cmdInit(args) {
|
|
|
4265
4388
|
}
|
|
4266
4389
|
let selectedBlueprint = "default";
|
|
4267
4390
|
let registrySource = "cache";
|
|
4391
|
+
const preferContractOnly = brownfieldAttach && !requestedBlueprint && !requestedArchetype;
|
|
4268
4392
|
if (args.yes) {
|
|
4269
4393
|
selectedBlueprint = args.blueprint || "default";
|
|
4270
4394
|
} else if (!apiAvailable) {
|
|
@@ -4299,7 +4423,7 @@ ${YELLOW9}You're offline. Scaffolding minimal Decantr project.${RESET13}`);
|
|
|
4299
4423
|
${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
4300
4424
|
console.log(dim3("Run `decantr upgrade` when online, or visit decantr.ai/registry\n"));
|
|
4301
4425
|
selectedBlueprint = "default";
|
|
4302
|
-
} else {
|
|
4426
|
+
} else if (!preferContractOnly) {
|
|
4303
4427
|
console.log(dim3("Fetching registry content..."));
|
|
4304
4428
|
const blueprintsResult2 = await registryClient.fetchBlueprints();
|
|
4305
4429
|
registrySource = blueprintsResult2.source.type === "api" ? "api" : "cache";
|
|
@@ -4327,9 +4451,9 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
4327
4451
|
if (args.yes || selectedBlueprint !== "default") {
|
|
4328
4452
|
const flags = parseFlags(args, detected);
|
|
4329
4453
|
flags.blueprint = selectedBlueprint !== "default" ? selectedBlueprint : flags.blueprint;
|
|
4330
|
-
options = mergeWithDefaults(flags, detected);
|
|
4454
|
+
options = mergeWithDefaults(flags, detected, workflowSeed ?? void 0);
|
|
4331
4455
|
} else {
|
|
4332
|
-
options = await runInteractivePrompts(detected, archetypes, blueprints, themes);
|
|
4456
|
+
options = await runInteractivePrompts(detected, archetypes, blueprints, themes, workflowSeed ?? void 0);
|
|
4333
4457
|
userExplicit.theme = true;
|
|
4334
4458
|
userExplicit.mode = true;
|
|
4335
4459
|
userExplicit.shape = true;
|
|
@@ -4512,6 +4636,11 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
4512
4636
|
if (result.gitignoreUpdated) {
|
|
4513
4637
|
console.log(` ${dim3(".gitignore updated")}`);
|
|
4514
4638
|
}
|
|
4639
|
+
if (!existsSync25(join26(projectRoot, "package.json"))) {
|
|
4640
|
+
console.log("");
|
|
4641
|
+
console.log(dim3(` Note: ${cyan3("decantr init")} created Decantr contract/context files only.`));
|
|
4642
|
+
console.log(dim3(` For a runnable starter in a new directory, prefer ${cyan3("decantr new <name> --blueprint=...")}.`));
|
|
4643
|
+
}
|
|
4515
4644
|
console.log("");
|
|
4516
4645
|
console.log(" Next steps:");
|
|
4517
4646
|
console.log(" 1. Read DECANTR.md for methodology, CSS approach, and guard rules");
|
|
@@ -4529,7 +4658,7 @@ ${YELLOW9}You're offline. Scaffolding Decantr default.${RESET13}`);
|
|
|
4529
4658
|
console.log(` ${cyan3("decantr upgrade")} Update to latest patterns`);
|
|
4530
4659
|
console.log(` ${cyan3("decantr check")} Detect drift issues`);
|
|
4531
4660
|
console.log(` ${cyan3("decantr migrate")} Migrate v2 essence to v3`);
|
|
4532
|
-
const essenceContent =
|
|
4661
|
+
const essenceContent = readFileSync17(result.essencePath, "utf-8");
|
|
4533
4662
|
const essence = JSON.parse(essenceContent);
|
|
4534
4663
|
if (essence.version !== "3.1.0") {
|
|
4535
4664
|
const validation = validateEssence2(essence);
|
|
@@ -4576,16 +4705,16 @@ Validation warnings: ${validation.errors.join(", ")}`));
|
|
|
4576
4705
|
}
|
|
4577
4706
|
async function cmdStatus() {
|
|
4578
4707
|
const projectRoot = process.cwd();
|
|
4579
|
-
const essencePath =
|
|
4580
|
-
const projectJsonPath =
|
|
4708
|
+
const essencePath = join26(projectRoot, "decantr.essence.json");
|
|
4709
|
+
const projectJsonPath = join26(projectRoot, ".decantr", "project.json");
|
|
4581
4710
|
console.log(heading2("Decantr Project Status"));
|
|
4582
|
-
if (!
|
|
4711
|
+
if (!existsSync25(essencePath)) {
|
|
4583
4712
|
console.log(`${RED11}No decantr.essence.json found.${RESET13}`);
|
|
4584
4713
|
console.log(dim3('Run "decantr init" to create one.'));
|
|
4585
4714
|
return;
|
|
4586
4715
|
}
|
|
4587
4716
|
try {
|
|
4588
|
-
const essence = JSON.parse(
|
|
4717
|
+
const essence = JSON.parse(readFileSync17(essencePath, "utf-8"));
|
|
4589
4718
|
const validation = validateEssence2(essence);
|
|
4590
4719
|
const essenceVersion = isV36(essence) ? "v3" : "v2";
|
|
4591
4720
|
console.log(`${BOLD6}Essence:${RESET13}`);
|
|
@@ -4634,9 +4763,9 @@ async function cmdStatus() {
|
|
|
4634
4763
|
}
|
|
4635
4764
|
console.log("");
|
|
4636
4765
|
console.log(`${BOLD6}Sync Status:${RESET13}`);
|
|
4637
|
-
if (
|
|
4766
|
+
if (existsSync25(projectJsonPath)) {
|
|
4638
4767
|
try {
|
|
4639
|
-
const projectJson = JSON.parse(
|
|
4768
|
+
const projectJson = JSON.parse(readFileSync17(projectJsonPath, "utf-8"));
|
|
4640
4769
|
const syncStatus = projectJson.sync?.status || "unknown";
|
|
4641
4770
|
const lastSync = projectJson.sync?.lastSync || "never";
|
|
4642
4771
|
const source = projectJson.sync?.registrySource || "unknown";
|
|
@@ -4654,7 +4783,7 @@ async function cmdStatus() {
|
|
|
4654
4783
|
}
|
|
4655
4784
|
async function cmdSync() {
|
|
4656
4785
|
const projectRoot = process.cwd();
|
|
4657
|
-
const cacheDir =
|
|
4786
|
+
const cacheDir = join26(projectRoot, ".decantr", "cache");
|
|
4658
4787
|
console.log(heading2("Syncing registry content..."));
|
|
4659
4788
|
const result = await syncRegistry(cacheDir);
|
|
4660
4789
|
if (result.synced.length > 0) {
|
|
@@ -4843,14 +4972,14 @@ ${BOLD6}Examples:${RESET13}
|
|
|
4843
4972
|
process.exitCode = 1;
|
|
4844
4973
|
return;
|
|
4845
4974
|
}
|
|
4846
|
-
const themePath =
|
|
4847
|
-
if (!
|
|
4975
|
+
const themePath = join26(projectRoot, ".decantr", "custom", "themes", `${name}.json`);
|
|
4976
|
+
if (!existsSync25(themePath)) {
|
|
4848
4977
|
console.error(error3(`Theme "${name}" not found at ${themePath}`));
|
|
4849
4978
|
process.exitCode = 1;
|
|
4850
4979
|
return;
|
|
4851
4980
|
}
|
|
4852
4981
|
try {
|
|
4853
|
-
const theme = JSON.parse(
|
|
4982
|
+
const theme = JSON.parse(readFileSync17(themePath, "utf-8"));
|
|
4854
4983
|
const result = validateCustomTheme(theme);
|
|
4855
4984
|
if (result.valid) {
|
|
4856
4985
|
console.log(success3(`Custom theme "${name}" is valid`));
|
|
@@ -4966,9 +5095,9 @@ ${BOLD6}Init Options:${RESET13}
|
|
|
4966
5095
|
--registry Custom registry URL
|
|
4967
5096
|
|
|
4968
5097
|
${BOLD6}Commands:${RESET13}
|
|
4969
|
-
${cyan3("new")} Create a new
|
|
4970
|
-
${cyan3("magic")}
|
|
4971
|
-
${cyan3("init")}
|
|
5098
|
+
${cyan3("new")} Create a new greenfield workspace and bootstrap the available starter adapter
|
|
5099
|
+
${cyan3("magic")} Greenfield-first intent flow; steers existing apps into analyze + init
|
|
5100
|
+
${cyan3("init")} Attach Decantr contract/context files to an existing project or empty workspace
|
|
4972
5101
|
${cyan3("status")} Show project status, DNA axioms, and blueprint info
|
|
4973
5102
|
${cyan3("sync")} Sync registry content from API
|
|
4974
5103
|
${cyan3("audit")} Audit the project or critique a specific file against compiled packs
|
|
@@ -4986,7 +5115,7 @@ ${BOLD6}Commands:${RESET13}
|
|
|
4986
5115
|
${cyan3("publish")} Publish a custom content item to the community registry
|
|
4987
5116
|
${cyan3("login")} Authenticate with the Decantr registry
|
|
4988
5117
|
${cyan3("logout")} Remove stored credentials
|
|
4989
|
-
${cyan3("analyze")}
|
|
5118
|
+
${cyan3("analyze")} Brownfield entrypoint: scan an existing project and emit attach guidance
|
|
4990
5119
|
${cyan3("export")} Export design tokens to framework format (shadcn, tailwind, css-vars)
|
|
4991
5120
|
${cyan3("registry")} Registry management and intelligence summary
|
|
4992
5121
|
${cyan3("upgrade")} Check for content updates from registry
|
|
@@ -4996,7 +5125,7 @@ ${BOLD6}Examples:${RESET13}
|
|
|
4996
5125
|
decantr new my-app --blueprint=carbon-ai-portal
|
|
4997
5126
|
decantr magic "AI chatbot with dark cyber theme \u2014 bold and futuristic"
|
|
4998
5127
|
decantr init
|
|
4999
|
-
decantr init --blueprint=saas-dashboard --theme=luminarum --yes
|
|
5128
|
+
decantr init --existing --blueprint=saas-dashboard --theme=luminarum --yes
|
|
5000
5129
|
decantr status
|
|
5001
5130
|
decantr audit
|
|
5002
5131
|
decantr audit src/pages/HomePage.tsx
|
|
@@ -5017,6 +5146,15 @@ ${BOLD6}Examples:${RESET13}
|
|
|
5017
5146
|
decantr registry audit-project --namespace @official --json
|
|
5018
5147
|
decantr registry audit-project --namespace @official --dist dist --sources src
|
|
5019
5148
|
decantr create pattern my-card
|
|
5149
|
+
|
|
5150
|
+
${BOLD6}Workflow Model:${RESET13}
|
|
5151
|
+
${cyan3("Greenfield blueprint")} decantr new / decantr magic
|
|
5152
|
+
${cyan3("Brownfield adoption")} decantr analyze -> decantr init --existing
|
|
5153
|
+
${cyan3("Hybrid composition")} decantr add/remove, decantr theme switch, decantr registry, decantr upgrade
|
|
5154
|
+
|
|
5155
|
+
${BOLD6}Bootstrap adapters:${RESET13}
|
|
5156
|
+
Current runnable starter adapter: ${cyan3("react-vite")}
|
|
5157
|
+
Other contract targets stay framework-agnostic, but currently initialize in contract-only mode until their starter adapters land.
|
|
5020
5158
|
`);
|
|
5021
5159
|
}
|
|
5022
5160
|
async function main() {
|
|
@@ -5095,7 +5233,7 @@ async function main() {
|
|
|
5095
5233
|
break;
|
|
5096
5234
|
}
|
|
5097
5235
|
case "upgrade": {
|
|
5098
|
-
const { cmdUpgrade } = await import("./upgrade-
|
|
5236
|
+
const { cmdUpgrade } = await import("./upgrade-WE7Y7ZOE.js");
|
|
5099
5237
|
const applyFlag = args.includes("--apply");
|
|
5100
5238
|
await cmdUpgrade(process.cwd(), { apply: applyFlag });
|
|
5101
5239
|
break;
|