create-fornix 0.0.9 → 0.0.10
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/dist/index.js +358 -103
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -216,6 +216,7 @@ function topologicalSort(blocks, manifests) {
|
|
|
216
216
|
function generateStructure(config, manifests = []) {
|
|
217
217
|
const files = {};
|
|
218
218
|
const adapterDeps = getAdapterDependencies(config);
|
|
219
|
+
const blockDeps = getBlockDependencies(manifests);
|
|
219
220
|
const pkg = {
|
|
220
221
|
name: config.projectName,
|
|
221
222
|
type: "module",
|
|
@@ -234,10 +235,14 @@ function generateStructure(config, manifests = []) {
|
|
|
234
235
|
tailwindcss: "^4.0.0",
|
|
235
236
|
"@tailwindcss/vite": "^4.0.0"
|
|
236
237
|
},
|
|
237
|
-
...adapterDeps
|
|
238
|
+
...adapterDeps,
|
|
239
|
+
...blockDeps
|
|
238
240
|
},
|
|
239
241
|
devDependencies: {
|
|
240
|
-
typescript: "^5.7.0"
|
|
242
|
+
typescript: "^5.7.0",
|
|
243
|
+
...config.deployTarget === "cloudflare" && {
|
|
244
|
+
"@cloudflare/workers-types": "^4.0.0"
|
|
245
|
+
}
|
|
241
246
|
}
|
|
242
247
|
};
|
|
243
248
|
files["package.json"] = JSON.stringify(pkg, null, 2) + "\n";
|
|
@@ -246,9 +251,11 @@ function generateStructure(config, manifests = []) {
|
|
|
246
251
|
compilerOptions: {
|
|
247
252
|
jsx: "preserve",
|
|
248
253
|
jsxImportSource: "react",
|
|
249
|
-
// Even if not using React yet, good default for UI frameworks
|
|
250
254
|
strictNullChecks: true,
|
|
251
255
|
baseUrl: ".",
|
|
256
|
+
...config.deployTarget === "cloudflare" && {
|
|
257
|
+
types: ["@cloudflare/workers-types"]
|
|
258
|
+
},
|
|
252
259
|
paths: {
|
|
253
260
|
"@/*": ["src/*"]
|
|
254
261
|
}
|
|
@@ -278,42 +285,59 @@ pnpm-debug.log*
|
|
|
278
285
|
.DS_Store
|
|
279
286
|
Thumbs.db
|
|
280
287
|
`.trim() + "\n";
|
|
281
|
-
const
|
|
282
|
-
const
|
|
288
|
+
const LAYOUT_CATEGORIES2 = /* @__PURE__ */ new Set(["header", "footer"]);
|
|
289
|
+
const headerImports = [];
|
|
290
|
+
const headerComponents = [];
|
|
291
|
+
const contentImports = [];
|
|
292
|
+
const contentComponents = [];
|
|
293
|
+
const footerImports = [];
|
|
294
|
+
const footerComponents = [];
|
|
283
295
|
if (manifests.length > 0) {
|
|
284
296
|
for (const manifest2 of manifests) {
|
|
285
297
|
if (manifest2.type !== "section") continue;
|
|
286
298
|
const mainFile = manifest2.files.find((f) => f.destination.endsWith(".astro") || f.destination.endsWith(".tsx"));
|
|
287
|
-
if (mainFile)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
299
|
+
if (!mainFile) continue;
|
|
300
|
+
const componentName = manifest2.name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
301
|
+
let importPath = mainFile.destination;
|
|
302
|
+
if (importPath.startsWith("src/")) {
|
|
303
|
+
importPath = "../" + importPath.substring(4);
|
|
304
|
+
}
|
|
305
|
+
const category = manifest2.category ?? "other";
|
|
306
|
+
if (category === "header") {
|
|
307
|
+
headerImports.push(`import ${componentName} from '${importPath}';`);
|
|
308
|
+
headerComponents.push(` <${componentName} />`);
|
|
309
|
+
} else if (category === "footer") {
|
|
310
|
+
footerImports.push(`import ${componentName} from '${importPath}';`);
|
|
311
|
+
footerComponents.push(` <${componentName} />`);
|
|
312
|
+
} else {
|
|
313
|
+
contentImports.push(`import ${componentName} from '${importPath}';`);
|
|
314
|
+
contentComponents.push(` <${componentName} />`);
|
|
295
315
|
}
|
|
296
316
|
}
|
|
297
317
|
}
|
|
298
318
|
const indexAstroContent = `
|
|
299
319
|
---
|
|
300
320
|
import Layout from '../layouts/Layout.astro';
|
|
301
|
-
${
|
|
321
|
+
${contentImports.join("\n")}
|
|
302
322
|
---
|
|
303
323
|
<Layout title="Welcome to ${config.projectName}.">
|
|
304
324
|
<main>
|
|
305
|
-
${
|
|
325
|
+
${contentComponents.length > 0 ? contentComponents.join("\n") : ` <h1>Welcome to <span class="text-gradient">${config.projectName}</span></h1>`}
|
|
306
326
|
</main>
|
|
307
327
|
</Layout>
|
|
308
328
|
`.trim() + "\n";
|
|
309
329
|
files["src/pages/index.astro"] = indexAstroContent;
|
|
310
330
|
const tailwindImport = config.cssEngine === "tailwind" ? '\nimport "../../tailwind.css";' : "";
|
|
331
|
+
const layoutImportsStr = [...headerImports, ...footerImports].join("\n");
|
|
332
|
+
const layoutImportSection = layoutImportsStr ? "\n" + layoutImportsStr : "";
|
|
333
|
+
const headerSection = headerComponents.length > 0 ? "\n" + headerComponents.join("\n") + "\n" : "";
|
|
334
|
+
const footerSection = footerComponents.length > 0 ? "\n" + footerComponents.join("\n") : "";
|
|
311
335
|
files["src/layouts/Layout.astro"] = `
|
|
312
336
|
---
|
|
313
337
|
interface Props {
|
|
314
338
|
title: string;
|
|
315
339
|
}
|
|
316
|
-
const { title } = Astro.props;${tailwindImport}
|
|
340
|
+
const { title } = Astro.props;${tailwindImport}${layoutImportSection}
|
|
317
341
|
---
|
|
318
342
|
<!doctype html>
|
|
319
343
|
<html lang="en">
|
|
@@ -325,8 +349,8 @@ const { title } = Astro.props;${tailwindImport}
|
|
|
325
349
|
<meta name="generator" content={Astro.generator} />
|
|
326
350
|
<title>{title}</title>
|
|
327
351
|
</head>
|
|
328
|
-
<body
|
|
329
|
-
<slot
|
|
352
|
+
<body>${headerSection}
|
|
353
|
+
<slot />${footerSection}
|
|
330
354
|
</body>
|
|
331
355
|
</html>
|
|
332
356
|
|
|
@@ -378,6 +402,15 @@ const { title } = Astro.props;${tailwindImport}
|
|
|
378
402
|
}
|
|
379
403
|
return files;
|
|
380
404
|
}
|
|
405
|
+
function getBlockDependencies(manifests) {
|
|
406
|
+
const merged = {};
|
|
407
|
+
for (const manifest2 of manifests) {
|
|
408
|
+
if (manifest2.dependencies) {
|
|
409
|
+
Object.assign(merged, manifest2.dependencies);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return merged;
|
|
413
|
+
}
|
|
381
414
|
function getAdapterDependencies(config) {
|
|
382
415
|
if (config.renderMode === "static" && config.deployTarget === "static") {
|
|
383
416
|
return {};
|
|
@@ -502,11 +535,35 @@ function buildPaletteFile(colors) {
|
|
|
502
535
|
const properties = COLOR_TOKENS.map(
|
|
503
536
|
(token) => ` --color-${token}: ${colors[token]};`
|
|
504
537
|
).join("\n");
|
|
538
|
+
const surface = blendHex(colors.background, colors.foreground, 0.08);
|
|
539
|
+
const muted = blendHex(colors.foreground, colors.background, 0.4);
|
|
540
|
+
const derived = [
|
|
541
|
+
` --color-surface: ${surface};`,
|
|
542
|
+
` --color-muted: ${muted};`
|
|
543
|
+
].join("\n");
|
|
505
544
|
return `:root {
|
|
506
545
|
${properties}
|
|
546
|
+
${derived}
|
|
507
547
|
}
|
|
508
548
|
`;
|
|
509
549
|
}
|
|
550
|
+
function blendHex(colorA, colorB, ratio) {
|
|
551
|
+
const a = parseHex(colorA);
|
|
552
|
+
const b = parseHex(colorB);
|
|
553
|
+
const r = Math.round(a.r + (b.r - a.r) * ratio);
|
|
554
|
+
const g = Math.round(a.g + (b.g - a.g) * ratio);
|
|
555
|
+
const bl = Math.round(a.b + (b.b - a.b) * ratio);
|
|
556
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
|
|
557
|
+
}
|
|
558
|
+
function parseHex(hex) {
|
|
559
|
+
const h = hex.replace("#", "");
|
|
560
|
+
const full = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
|
|
561
|
+
return {
|
|
562
|
+
r: parseInt(full.slice(0, 2), 16),
|
|
563
|
+
g: parseInt(full.slice(2, 4), 16),
|
|
564
|
+
b: parseInt(full.slice(4, 6), 16)
|
|
565
|
+
};
|
|
566
|
+
}
|
|
510
567
|
function buildSwitcherScript(paletteNames) {
|
|
511
568
|
return `(function () {
|
|
512
569
|
const PALETTES = ${JSON.stringify(paletteNames)};
|
|
@@ -706,8 +763,17 @@ function wireI18n(config, manifests) {
|
|
|
706
763
|
}
|
|
707
764
|
files["src/i18n/utils.ts"] = generateI18nUtils(config);
|
|
708
765
|
files["src/pages/[locale]/index.astro"] = generateLocaleIndexPage(config, manifests ?? []);
|
|
766
|
+
files["src/pages/index.astro"] = generateRootRedirect(config);
|
|
709
767
|
return ok(files);
|
|
710
768
|
}
|
|
769
|
+
function generateRootRedirect(config) {
|
|
770
|
+
const needsPrerender = config.renderMode === "server" || config.renderMode === "hybrid";
|
|
771
|
+
const prerenderLine = needsPrerender ? "export const prerender = true;\n" : "";
|
|
772
|
+
return `---
|
|
773
|
+
${prerenderLine}return Astro.redirect("/${config.defaultLocale}/");
|
|
774
|
+
---
|
|
775
|
+
`;
|
|
776
|
+
}
|
|
711
777
|
function generateI18nUtils(config) {
|
|
712
778
|
const localesArray = config.locales.map((locale) => `"${locale}"`).join(", ");
|
|
713
779
|
return `export const locales = [${localesArray}] as const;
|
|
@@ -741,22 +807,27 @@ export function t<T>(
|
|
|
741
807
|
`;
|
|
742
808
|
}
|
|
743
809
|
function generateLocaleIndexPage(config, manifests) {
|
|
744
|
-
const
|
|
810
|
+
const LAYOUT_CATEGORIES2 = /* @__PURE__ */ new Set(["header", "footer"]);
|
|
811
|
+
const contentBlocks = manifests.filter(
|
|
812
|
+
(m) => m.type === "section" && !LAYOUT_CATEGORIES2.has(m.category ?? "")
|
|
813
|
+
);
|
|
745
814
|
const imports = [];
|
|
746
815
|
const tags = [];
|
|
747
|
-
for (const block of
|
|
816
|
+
for (const block of contentBlocks) {
|
|
748
817
|
const componentName = block.name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
749
|
-
imports.push(`import ${componentName} from '
|
|
818
|
+
imports.push(`import ${componentName} from '../../components/sections/${block.name}.astro';`);
|
|
750
819
|
tags.push(` <${componentName} />`);
|
|
751
820
|
}
|
|
752
821
|
const importSection = imports.length > 0 ? imports.join("\n") + "\n" : "";
|
|
753
822
|
const blockSection = tags.length > 0 ? "\n" + tags.join("\n") + "\n " : "\n <h1>" + config.projectName + "</h1>\n <p>Locale: {locale}</p>\n ";
|
|
823
|
+
const needsPrerender = config.renderMode === "server" || config.renderMode === "hybrid";
|
|
824
|
+
const prerenderLine = needsPrerender ? "export const prerender = true;\n" : "";
|
|
754
825
|
return `---
|
|
755
|
-
import { locales } from "
|
|
756
|
-
import Layout from "
|
|
757
|
-
${importSection}
|
|
826
|
+
import { locales } from "../../i18n/utils";
|
|
827
|
+
import Layout from "../../layouts/Layout.astro";
|
|
828
|
+
${importSection}${prerenderLine}
|
|
758
829
|
export function getStaticPaths() {
|
|
759
|
-
return locales.map((locale) => ({ params: { locale } }));
|
|
830
|
+
return locales.map((locale: string) => ({ params: { locale } }));
|
|
760
831
|
}
|
|
761
832
|
|
|
762
833
|
const { locale } = Astro.params;
|
|
@@ -2193,16 +2264,38 @@ async function runManualFlow(input) {
|
|
|
2193
2264
|
]
|
|
2194
2265
|
});
|
|
2195
2266
|
if (p.isCancel(cssEngine)) return handleCancel();
|
|
2196
|
-
const
|
|
2197
|
-
|
|
2198
|
-
|
|
2267
|
+
const headerOptions = buildCategoryOptions(input.manifests, "header");
|
|
2268
|
+
const footerOptions = buildCategoryOptions(input.manifests, "footer");
|
|
2269
|
+
const contentOptions = buildContentBlockOptions(input.manifests);
|
|
2270
|
+
let selectedHeader;
|
|
2271
|
+
let selectedFooter;
|
|
2272
|
+
let selectedContentBlocks = [];
|
|
2273
|
+
if (headerOptions.length > 0) {
|
|
2274
|
+
const noneOption = { value: "__none__", label: "None", hint: "No header" };
|
|
2275
|
+
const headerChoice = await p.select({
|
|
2276
|
+
message: "Choose a header (appears on every page)",
|
|
2277
|
+
options: [noneOption, ...headerOptions]
|
|
2278
|
+
});
|
|
2279
|
+
if (p.isCancel(headerChoice)) return handleCancel();
|
|
2280
|
+
if (headerChoice !== "__none__") selectedHeader = headerChoice;
|
|
2281
|
+
}
|
|
2282
|
+
if (contentOptions.length > 0) {
|
|
2199
2283
|
const blocks = await p.multiselect({
|
|
2200
|
-
message: "Select blocks
|
|
2201
|
-
options:
|
|
2284
|
+
message: "Select content blocks (space to toggle, enter to confirm)",
|
|
2285
|
+
options: contentOptions,
|
|
2202
2286
|
required: false
|
|
2203
2287
|
});
|
|
2204
2288
|
if (p.isCancel(blocks)) return handleCancel();
|
|
2205
|
-
|
|
2289
|
+
selectedContentBlocks = blocks;
|
|
2290
|
+
}
|
|
2291
|
+
if (footerOptions.length > 0) {
|
|
2292
|
+
const noneOption = { value: "__none__", label: "None", hint: "No footer" };
|
|
2293
|
+
const footerChoice = await p.select({
|
|
2294
|
+
message: "Choose a footer (appears on every page)",
|
|
2295
|
+
options: [noneOption, ...footerOptions]
|
|
2296
|
+
});
|
|
2297
|
+
if (p.isCancel(footerChoice)) return handleCancel();
|
|
2298
|
+
if (footerChoice !== "__none__") selectedFooter = footerChoice;
|
|
2206
2299
|
}
|
|
2207
2300
|
const localesInput = await p.text({
|
|
2208
2301
|
message: "Locales (comma-separated, e.g. en,es,ar)",
|
|
@@ -2232,6 +2325,24 @@ async function runManualFlow(input) {
|
|
|
2232
2325
|
if (p.isCancel(switcherChoice)) return handleCancel();
|
|
2233
2326
|
themeSwitcher = switcherChoice;
|
|
2234
2327
|
}
|
|
2328
|
+
if (!selectedHeader && headerOptions.length > 0) {
|
|
2329
|
+
const needsNav = locales.length >= 2 || themeSwitcher;
|
|
2330
|
+
if (needsNav) {
|
|
2331
|
+
const autoHeader = await p.confirm({
|
|
2332
|
+
message: `You enabled ${locales.length >= 2 ? "multiple locales" : "theme switching"} \u2014 add a header for navigation?`,
|
|
2333
|
+
initialValue: true
|
|
2334
|
+
});
|
|
2335
|
+
if (p.isCancel(autoHeader)) return handleCancel();
|
|
2336
|
+
if (autoHeader) {
|
|
2337
|
+
selectedHeader = headerOptions[0].value;
|
|
2338
|
+
console.log(pc.dim(` Adding ${selectedHeader} for navigation.`));
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
const selectedBlocks = [];
|
|
2343
|
+
if (selectedHeader) selectedBlocks.push(selectedHeader);
|
|
2344
|
+
selectedBlocks.push(...selectedContentBlocks);
|
|
2345
|
+
if (selectedFooter) selectedBlocks.push(selectedFooter);
|
|
2235
2346
|
const config = {
|
|
2236
2347
|
projectName: projectName.trim(),
|
|
2237
2348
|
projectDir: `./${projectName.trim()}`,
|
|
@@ -2271,8 +2382,18 @@ function handleCancel() {
|
|
|
2271
2382
|
p.cancel("Operation cancelled.");
|
|
2272
2383
|
return null;
|
|
2273
2384
|
}
|
|
2274
|
-
function
|
|
2275
|
-
|
|
2385
|
+
function buildCategoryOptions(manifests, category) {
|
|
2386
|
+
return Object.values(manifests).filter((block) => (block.category ?? "other") === category).map((block) => ({
|
|
2387
|
+
value: block.name,
|
|
2388
|
+
label: block.name,
|
|
2389
|
+
hint: block.description
|
|
2390
|
+
}));
|
|
2391
|
+
}
|
|
2392
|
+
function buildContentBlockOptions(manifests) {
|
|
2393
|
+
const LAYOUT_CATEGORIES2 = /* @__PURE__ */ new Set(["header", "footer"]);
|
|
2394
|
+
const blocks = Object.values(manifests).filter(
|
|
2395
|
+
(block) => !LAYOUT_CATEGORIES2.has(block.category ?? "other")
|
|
2396
|
+
);
|
|
2276
2397
|
const categories = /* @__PURE__ */ new Map();
|
|
2277
2398
|
for (const block of blocks) {
|
|
2278
2399
|
const category = block.category ?? "other";
|
|
@@ -2286,7 +2407,7 @@ function buildBlockOptions(manifests) {
|
|
|
2286
2407
|
for (const block of categoryBlocks) {
|
|
2287
2408
|
options.push({
|
|
2288
2409
|
value: block.name,
|
|
2289
|
-
label:
|
|
2410
|
+
label: block.name,
|
|
2290
2411
|
hint: `${category} \u2014 ${block.description}`
|
|
2291
2412
|
});
|
|
2292
2413
|
}
|
|
@@ -4104,17 +4225,60 @@ function preResolveDependencies(selected, manifests) {
|
|
|
4104
4225
|
// src/cli/commands/add.ts
|
|
4105
4226
|
import { defineCommand as defineCommand2 } from "citty";
|
|
4106
4227
|
import pc4 from "picocolors";
|
|
4107
|
-
import { readFileSync as
|
|
4108
|
-
import { join as
|
|
4228
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
4229
|
+
import { join as join8, dirname as dirname3 } from "path";
|
|
4109
4230
|
|
|
4110
4231
|
// src/scaffold/page-updater.ts
|
|
4232
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
|
|
4233
|
+
import { join as join7 } from "path";
|
|
4234
|
+
var CATEGORY_ORDER = {
|
|
4235
|
+
header: 0,
|
|
4236
|
+
hero: 1,
|
|
4237
|
+
features: 2,
|
|
4238
|
+
pricing: 3,
|
|
4239
|
+
testimonials: 4,
|
|
4240
|
+
faq: 5,
|
|
4241
|
+
cta: 6,
|
|
4242
|
+
contact: 7,
|
|
4243
|
+
theme: 8,
|
|
4244
|
+
footer: 9
|
|
4245
|
+
};
|
|
4246
|
+
var DEFAULT_PRIORITY = 5;
|
|
4247
|
+
var LAYOUT_CATEGORIES = /* @__PURE__ */ new Set(["header", "footer"]);
|
|
4111
4248
|
function blockNameToComponentName(blockName) {
|
|
4112
4249
|
return blockName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4113
4250
|
}
|
|
4114
4251
|
function blockNameToImportPath(blockName) {
|
|
4115
4252
|
return `../components/sections/${blockName}.astro`;
|
|
4116
4253
|
}
|
|
4117
|
-
function
|
|
4254
|
+
function blockNameToLayoutImportPath(blockName) {
|
|
4255
|
+
return `../components/sections/${blockName}.astro`;
|
|
4256
|
+
}
|
|
4257
|
+
function getBlockCategory(blockName, projectDir) {
|
|
4258
|
+
if (projectDir) {
|
|
4259
|
+
try {
|
|
4260
|
+
const fornixPath = join7(projectDir, "fornix.json");
|
|
4261
|
+
if (existsSync4(fornixPath)) {
|
|
4262
|
+
const fornix = JSON.parse(readFileSync5(fornixPath, "utf-8"));
|
|
4263
|
+
const block = fornix.blocks?.find((b) => b.name === blockName);
|
|
4264
|
+
if (block?.category) return block.category;
|
|
4265
|
+
}
|
|
4266
|
+
} catch {
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
for (const prefix of Object.keys(CATEGORY_ORDER)) {
|
|
4270
|
+
if (blockName.startsWith(prefix)) return prefix;
|
|
4271
|
+
}
|
|
4272
|
+
return "other";
|
|
4273
|
+
}
|
|
4274
|
+
function getPriority(category) {
|
|
4275
|
+
return CATEGORY_ORDER[category] ?? DEFAULT_PRIORITY;
|
|
4276
|
+
}
|
|
4277
|
+
function isLayoutBlock(blockName, projectDir) {
|
|
4278
|
+
const category = getBlockCategory(blockName, projectDir);
|
|
4279
|
+
return LAYOUT_CATEGORIES.has(category);
|
|
4280
|
+
}
|
|
4281
|
+
function addBlockToPage(pageContent, blockName, projectDir) {
|
|
4118
4282
|
const componentName = blockNameToComponentName(blockName);
|
|
4119
4283
|
const importPath = blockNameToImportPath(blockName);
|
|
4120
4284
|
if (pageContent.includes(importPath) || pageContent.includes(`import ${componentName}`)) {
|
|
@@ -4122,14 +4286,67 @@ function addBlockToPage(pageContent, blockName) {
|
|
|
4122
4286
|
}
|
|
4123
4287
|
const importLine = `import ${componentName} from '${importPath}';`;
|
|
4124
4288
|
const componentTag = ` <${componentName} />`;
|
|
4289
|
+
const newCategory = getBlockCategory(blockName, projectDir);
|
|
4290
|
+
const newPriority = getPriority(newCategory);
|
|
4125
4291
|
const frontmatterEnd = pageContent.indexOf("---", pageContent.indexOf("---") + 3);
|
|
4126
4292
|
if (frontmatterEnd === -1) {
|
|
4127
4293
|
return pageContent;
|
|
4128
4294
|
}
|
|
4129
4295
|
let updated = pageContent.slice(0, frontmatterEnd) + importLine + "\n" + pageContent.slice(frontmatterEnd);
|
|
4296
|
+
const mainOpenMatch = updated.match(/<main[^>]*>/);
|
|
4130
4297
|
const mainCloseIndex = updated.lastIndexOf("</main>");
|
|
4131
|
-
if (mainCloseIndex
|
|
4132
|
-
|
|
4298
|
+
if (!mainOpenMatch || mainCloseIndex === -1) {
|
|
4299
|
+
return updated;
|
|
4300
|
+
}
|
|
4301
|
+
const mainOpenEnd = mainOpenMatch.index + mainOpenMatch[0].length;
|
|
4302
|
+
const mainContent = updated.slice(mainOpenEnd, mainCloseIndex);
|
|
4303
|
+
const tagPattern = /^(\s*<([A-Z][A-Za-z]*)\s*\/>)\s*$/gm;
|
|
4304
|
+
let insertOffset = mainCloseIndex;
|
|
4305
|
+
let match;
|
|
4306
|
+
while ((match = tagPattern.exec(mainContent)) !== null) {
|
|
4307
|
+
const existingComponentName = match[2];
|
|
4308
|
+
const existingBlockName = componentNameToBlockName(existingComponentName);
|
|
4309
|
+
const existingCategory = getBlockCategory(existingBlockName, projectDir);
|
|
4310
|
+
const existingPriority = getPriority(existingCategory);
|
|
4311
|
+
if (existingPriority > newPriority) {
|
|
4312
|
+
insertOffset = mainOpenEnd + match.index;
|
|
4313
|
+
break;
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
updated = updated.slice(0, insertOffset) + componentTag + "\n" + updated.slice(insertOffset);
|
|
4317
|
+
return updated;
|
|
4318
|
+
}
|
|
4319
|
+
function addBlockToLayout(layoutContent, blockName, projectDir) {
|
|
4320
|
+
const componentName = blockNameToComponentName(blockName);
|
|
4321
|
+
const importPath = blockNameToLayoutImportPath(blockName);
|
|
4322
|
+
if (layoutContent.includes(importPath) || layoutContent.includes(`import ${componentName}`)) {
|
|
4323
|
+
return layoutContent;
|
|
4324
|
+
}
|
|
4325
|
+
const importLine = `import ${componentName} from '${importPath}';`;
|
|
4326
|
+
const componentTag = ` <${componentName} />`;
|
|
4327
|
+
const category = getBlockCategory(blockName, projectDir);
|
|
4328
|
+
const frontmatterEnd = layoutContent.indexOf("---", layoutContent.indexOf("---") + 3);
|
|
4329
|
+
if (frontmatterEnd === -1) {
|
|
4330
|
+
return layoutContent;
|
|
4331
|
+
}
|
|
4332
|
+
let updated = layoutContent.slice(0, frontmatterEnd) + importLine + "\n" + layoutContent.slice(frontmatterEnd);
|
|
4333
|
+
if (category === "header") {
|
|
4334
|
+
const slotIndex = updated.indexOf("<slot");
|
|
4335
|
+
const mainIndex = updated.indexOf("<main");
|
|
4336
|
+
const insertBefore = mainIndex !== -1 ? mainIndex : slotIndex;
|
|
4337
|
+
if (insertBefore !== -1) {
|
|
4338
|
+
updated = updated.slice(0, insertBefore) + componentTag + "\n" + updated.slice(insertBefore);
|
|
4339
|
+
}
|
|
4340
|
+
} else if (category === "footer") {
|
|
4341
|
+
const mainCloseIndex = updated.indexOf("</main>");
|
|
4342
|
+
const slotMatch = updated.match(/<slot\s*\/>/);
|
|
4343
|
+
if (mainCloseIndex !== -1) {
|
|
4344
|
+
const afterMain = mainCloseIndex + "</main>".length;
|
|
4345
|
+
updated = updated.slice(0, afterMain) + "\n" + componentTag + updated.slice(afterMain);
|
|
4346
|
+
} else if (slotMatch) {
|
|
4347
|
+
const afterSlot = slotMatch.index + slotMatch[0].length;
|
|
4348
|
+
updated = updated.slice(0, afterSlot) + "\n" + componentTag + updated.slice(afterSlot);
|
|
4349
|
+
}
|
|
4133
4350
|
}
|
|
4134
4351
|
return updated;
|
|
4135
4352
|
}
|
|
@@ -4152,6 +4369,9 @@ function removeBlockFromPage(pageContent, blockName) {
|
|
|
4152
4369
|
function escapeRegex(str) {
|
|
4153
4370
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4154
4371
|
}
|
|
4372
|
+
function componentNameToBlockName(componentName) {
|
|
4373
|
+
return componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
4374
|
+
}
|
|
4155
4375
|
|
|
4156
4376
|
// src/cli/commands/add.ts
|
|
4157
4377
|
var addCommand = defineCommand2({
|
|
@@ -4184,14 +4404,14 @@ var addCommand = defineCommand2({
|
|
|
4184
4404
|
async run({ args: args2 }) {
|
|
4185
4405
|
const typedArgs = args2;
|
|
4186
4406
|
const cwd = process.cwd();
|
|
4187
|
-
const manifestPath =
|
|
4188
|
-
if (!
|
|
4407
|
+
const manifestPath = join8(cwd, "fornix.json");
|
|
4408
|
+
if (!existsSync5(manifestPath)) {
|
|
4189
4409
|
console.error(
|
|
4190
4410
|
pc4.red("\u2717 No fornix.json found. Are you in a Fornix project?")
|
|
4191
4411
|
);
|
|
4192
4412
|
process.exit(1);
|
|
4193
4413
|
}
|
|
4194
|
-
const manifestRaw =
|
|
4414
|
+
const manifestRaw = readFileSync6(manifestPath, "utf-8");
|
|
4195
4415
|
const manifest2 = JSON.parse(manifestRaw);
|
|
4196
4416
|
const registryResult = await fetchRegistryIndex();
|
|
4197
4417
|
if (!isOk(registryResult)) {
|
|
@@ -4220,6 +4440,27 @@ var addCommand = defineCommand2({
|
|
|
4220
4440
|
return;
|
|
4221
4441
|
}
|
|
4222
4442
|
const blocksToAdd = resolveDependencies2(blockName, installedNames, manifests);
|
|
4443
|
+
for (const name of blocksToAdd) {
|
|
4444
|
+
const m = manifests[name];
|
|
4445
|
+
if (m?.conflicts && m.conflicts.length > 0) {
|
|
4446
|
+
for (const conflictName of m.conflicts) {
|
|
4447
|
+
if (installedNames.has(conflictName)) {
|
|
4448
|
+
console.error(
|
|
4449
|
+
pc4.red(
|
|
4450
|
+
`\u2717 Block '${name}' conflicts with installed block '${conflictName}'.`
|
|
4451
|
+
)
|
|
4452
|
+
);
|
|
4453
|
+
console.log(
|
|
4454
|
+
pc4.dim(
|
|
4455
|
+
` Remove '${conflictName}' first: npx create-fornix remove ${conflictName}`
|
|
4456
|
+
)
|
|
4457
|
+
);
|
|
4458
|
+
process.exitCode = 1;
|
|
4459
|
+
return;
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4223
4464
|
for (const name of blocksToAdd) {
|
|
4224
4465
|
const m = manifests[name];
|
|
4225
4466
|
if (m?.requiredMode && manifest2.renderMode !== m.requiredMode) {
|
|
@@ -4257,7 +4498,7 @@ var addCommand = defineCommand2({
|
|
|
4257
4498
|
return;
|
|
4258
4499
|
}
|
|
4259
4500
|
filesToWrite.push({
|
|
4260
|
-
path:
|
|
4501
|
+
path: join8(cwd, file.destination),
|
|
4261
4502
|
content
|
|
4262
4503
|
});
|
|
4263
4504
|
}
|
|
@@ -4296,18 +4537,31 @@ var addCommand = defineCommand2({
|
|
|
4296
4537
|
});
|
|
4297
4538
|
}
|
|
4298
4539
|
writeFileSync5(manifestPath, JSON.stringify(manifest2, null, 2) + "\n");
|
|
4299
|
-
const indexPath =
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4540
|
+
const indexPath = join8(cwd, "src/pages/index.astro");
|
|
4541
|
+
const layoutPath = join8(cwd, "src/layouts/Layout.astro");
|
|
4542
|
+
for (const name of blocksToAdd) {
|
|
4543
|
+
const bManifest = manifests[name];
|
|
4544
|
+
if (!bManifest || bManifest.type !== "section") continue;
|
|
4545
|
+
if (isLayoutBlock(name, cwd)) {
|
|
4546
|
+
if (existsSync5(layoutPath)) {
|
|
4547
|
+
const layoutContent = readFileSync6(layoutPath, "utf-8");
|
|
4548
|
+
const updated = addBlockToLayout(layoutContent, name, cwd);
|
|
4549
|
+
if (updated !== layoutContent) {
|
|
4550
|
+
writeFileSync5(layoutPath, updated);
|
|
4551
|
+
if (typedArgs.verbose) {
|
|
4552
|
+
console.log(` ${pc4.dim("\u270E")} updated Layout.astro (${name})`);
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
} else {
|
|
4557
|
+
if (existsSync5(indexPath)) {
|
|
4558
|
+
let pageContent = readFileSync6(indexPath, "utf-8");
|
|
4559
|
+
pageContent = addBlockToPage(pageContent, name, cwd);
|
|
4560
|
+
writeFileSync5(indexPath, pageContent);
|
|
4561
|
+
if (typedArgs.verbose) {
|
|
4562
|
+
console.log(` ${pc4.dim("\u270E")} updated index.astro (${name})`);
|
|
4563
|
+
}
|
|
4306
4564
|
}
|
|
4307
|
-
}
|
|
4308
|
-
writeFileSync5(indexPath, pageContent);
|
|
4309
|
-
if (typedArgs.verbose) {
|
|
4310
|
-
console.log(` ${pc4.dim("\u270E")} updated index.astro`);
|
|
4311
4565
|
}
|
|
4312
4566
|
}
|
|
4313
4567
|
console.log();
|
|
@@ -4350,8 +4604,8 @@ function resolveDependencies2(blockName, installedNames, manifests) {
|
|
|
4350
4604
|
// src/cli/commands/remove.ts
|
|
4351
4605
|
import { defineCommand as defineCommand3 } from "citty";
|
|
4352
4606
|
import pc5 from "picocolors";
|
|
4353
|
-
import { readFileSync as
|
|
4354
|
-
import { join as
|
|
4607
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync6, unlinkSync, readdirSync as readdirSync3, rmdirSync } from "fs";
|
|
4608
|
+
import { join as join9, dirname as dirname4 } from "path";
|
|
4355
4609
|
var removeCommand = defineCommand3({
|
|
4356
4610
|
meta: {
|
|
4357
4611
|
name: "remove",
|
|
@@ -4382,14 +4636,14 @@ var removeCommand = defineCommand3({
|
|
|
4382
4636
|
async run({ args: args2 }) {
|
|
4383
4637
|
const typedArgs = args2;
|
|
4384
4638
|
const cwd = process.cwd();
|
|
4385
|
-
const manifestPath =
|
|
4386
|
-
if (!
|
|
4639
|
+
const manifestPath = join9(cwd, "fornix.json");
|
|
4640
|
+
if (!existsSync6(manifestPath)) {
|
|
4387
4641
|
console.error(
|
|
4388
4642
|
pc5.red("\u2717 No fornix.json found. Are you in a Fornix project?")
|
|
4389
4643
|
);
|
|
4390
4644
|
process.exit(1);
|
|
4391
4645
|
}
|
|
4392
|
-
const manifestRaw =
|
|
4646
|
+
const manifestRaw = readFileSync7(manifestPath, "utf-8");
|
|
4393
4647
|
const manifest2 = JSON.parse(manifestRaw);
|
|
4394
4648
|
const registryResult = await fetchRegistryIndex();
|
|
4395
4649
|
if (!isOk(registryResult)) {
|
|
@@ -4422,8 +4676,8 @@ var removeCommand = defineCommand3({
|
|
|
4422
4676
|
const filesToRemove = [];
|
|
4423
4677
|
if (blockManifest) {
|
|
4424
4678
|
for (const file of blockManifest.files) {
|
|
4425
|
-
const filePath =
|
|
4426
|
-
if (
|
|
4679
|
+
const filePath = join9(cwd, file.destination);
|
|
4680
|
+
if (existsSync6(filePath)) {
|
|
4427
4681
|
filesToRemove.push(filePath);
|
|
4428
4682
|
}
|
|
4429
4683
|
}
|
|
@@ -4446,14 +4700,15 @@ var removeCommand = defineCommand3({
|
|
|
4446
4700
|
}
|
|
4447
4701
|
manifest2.blocks = manifest2.blocks.filter((b) => b.name !== blockName);
|
|
4448
4702
|
writeFileSync6(manifestPath, JSON.stringify(manifest2, null, 2) + "\n");
|
|
4449
|
-
const
|
|
4450
|
-
|
|
4451
|
-
|
|
4703
|
+
const targetFile = isLayoutBlock(blockName, cwd) ? join9(cwd, "src/layouts/Layout.astro") : join9(cwd, "src/pages/index.astro");
|
|
4704
|
+
const targetLabel = isLayoutBlock(blockName, cwd) ? "Layout.astro" : "index.astro";
|
|
4705
|
+
if (existsSync6(targetFile)) {
|
|
4706
|
+
const original = readFileSync7(targetFile, "utf-8");
|
|
4452
4707
|
const updated = removeBlockFromPage(original, blockName);
|
|
4453
4708
|
if (updated !== original) {
|
|
4454
|
-
writeFileSync6(
|
|
4709
|
+
writeFileSync6(targetFile, updated);
|
|
4455
4710
|
if (typedArgs.verbose) {
|
|
4456
|
-
console.log(` ${pc5.dim("\u270E")} updated
|
|
4711
|
+
console.log(` ${pc5.dim("\u270E")} updated ${targetLabel}`);
|
|
4457
4712
|
}
|
|
4458
4713
|
}
|
|
4459
4714
|
}
|
|
@@ -4628,8 +4883,8 @@ function printFormatted(blocks, verbose) {
|
|
|
4628
4883
|
// src/cli/commands/status.ts
|
|
4629
4884
|
import { defineCommand as defineCommand5 } from "citty";
|
|
4630
4885
|
import pc7 from "picocolors";
|
|
4631
|
-
import { readFileSync as
|
|
4632
|
-
import { join as
|
|
4886
|
+
import { readFileSync as readFileSync8, existsSync as existsSync7 } from "fs";
|
|
4887
|
+
import { join as join10 } from "path";
|
|
4633
4888
|
var statusCommand = defineCommand5({
|
|
4634
4889
|
meta: {
|
|
4635
4890
|
name: "status",
|
|
@@ -4650,8 +4905,8 @@ var statusCommand = defineCommand5({
|
|
|
4650
4905
|
run({ args: args2 }) {
|
|
4651
4906
|
const typedArgs = args2;
|
|
4652
4907
|
const cwd = process.cwd();
|
|
4653
|
-
const manifestPath =
|
|
4654
|
-
if (!
|
|
4908
|
+
const manifestPath = join10(cwd, "fornix.json");
|
|
4909
|
+
if (!existsSync7(manifestPath)) {
|
|
4655
4910
|
console.error(
|
|
4656
4911
|
pc7.red("\u2717 No fornix.json found in the current directory.")
|
|
4657
4912
|
);
|
|
@@ -4664,7 +4919,7 @@ var statusCommand = defineCommand5({
|
|
|
4664
4919
|
}
|
|
4665
4920
|
let manifest2;
|
|
4666
4921
|
try {
|
|
4667
|
-
const raw =
|
|
4922
|
+
const raw = readFileSync8(manifestPath, "utf-8");
|
|
4668
4923
|
manifest2 = JSON.parse(raw);
|
|
4669
4924
|
} catch {
|
|
4670
4925
|
console.error(pc7.red("\u2717 Failed to parse fornix.json."));
|
|
@@ -4745,8 +5000,8 @@ function printStatus(manifest2, verbose) {
|
|
|
4745
5000
|
// src/cli/commands/doctor.ts
|
|
4746
5001
|
import { defineCommand as defineCommand6 } from "citty";
|
|
4747
5002
|
import pc8 from "picocolors";
|
|
4748
|
-
import { readFileSync as
|
|
4749
|
-
import { join as
|
|
5003
|
+
import { readFileSync as readFileSync9, existsSync as existsSync8 } from "fs";
|
|
5004
|
+
import { join as join11 } from "path";
|
|
4750
5005
|
var doctorCommand = defineCommand6({
|
|
4751
5006
|
meta: {
|
|
4752
5007
|
name: "doctor",
|
|
@@ -4761,7 +5016,7 @@ var doctorCommand = defineCommand6({
|
|
|
4761
5016
|
},
|
|
4762
5017
|
async run({ args: args2 }) {
|
|
4763
5018
|
const cwd = process.cwd();
|
|
4764
|
-
const manifestPath =
|
|
5019
|
+
const manifestPath = join11(cwd, "fornix.json");
|
|
4765
5020
|
let hasErrors = false;
|
|
4766
5021
|
const errors = [];
|
|
4767
5022
|
function reportError(msg) {
|
|
@@ -4771,7 +5026,7 @@ var doctorCommand = defineCommand6({
|
|
|
4771
5026
|
console.error(pc8.red(`\u2717 ${msg}`));
|
|
4772
5027
|
}
|
|
4773
5028
|
}
|
|
4774
|
-
if (!
|
|
5029
|
+
if (!existsSync8(manifestPath)) {
|
|
4775
5030
|
reportError("No fornix.json found in the current directory.");
|
|
4776
5031
|
if (args2.json) {
|
|
4777
5032
|
console.log(JSON.stringify({ healthy: false, errors }));
|
|
@@ -4780,7 +5035,7 @@ var doctorCommand = defineCommand6({
|
|
|
4780
5035
|
}
|
|
4781
5036
|
let manifest2;
|
|
4782
5037
|
try {
|
|
4783
|
-
const raw =
|
|
5038
|
+
const raw = readFileSync9(manifestPath, "utf-8");
|
|
4784
5039
|
manifest2 = JSON.parse(raw);
|
|
4785
5040
|
} catch {
|
|
4786
5041
|
reportError("Failed to parse fornix.json.");
|
|
@@ -4806,8 +5061,8 @@ var doctorCommand = defineCommand6({
|
|
|
4806
5061
|
const bManifest = manifests[block.name];
|
|
4807
5062
|
if (bManifest) {
|
|
4808
5063
|
for (const file of bManifest.files) {
|
|
4809
|
-
const filePath =
|
|
4810
|
-
if (!
|
|
5064
|
+
const filePath = join11(cwd, file.destination);
|
|
5065
|
+
if (!existsSync8(filePath)) {
|
|
4811
5066
|
reportError(`Missing expected file for installed block '${block.name}': ${file.destination}`);
|
|
4812
5067
|
}
|
|
4813
5068
|
}
|
|
@@ -4816,7 +5071,7 @@ var doctorCommand = defineCommand6({
|
|
|
4816
5071
|
for (const [name, bManifest] of Object.entries(manifests)) {
|
|
4817
5072
|
if (!installedBlocks.has(name)) {
|
|
4818
5073
|
const foundOrphaned = bManifest.files.some((file) => {
|
|
4819
|
-
return
|
|
5074
|
+
return existsSync8(join11(cwd, file.destination));
|
|
4820
5075
|
});
|
|
4821
5076
|
if (foundOrphaned) {
|
|
4822
5077
|
reportError(`Orphaned block files detected for '${name}'. The block is not in fornix.json.`);
|
|
@@ -4840,14 +5095,14 @@ var doctorCommand = defineCommand6({
|
|
|
4840
5095
|
if (locale !== "") {
|
|
4841
5096
|
pathFragment = `src/content/${locale}/${subdirectory}/${bManifest.name}.json`;
|
|
4842
5097
|
}
|
|
4843
|
-
if (!
|
|
5098
|
+
if (!existsSync8(join11(cwd, pathFragment))) {
|
|
4844
5099
|
missingContentFiles.push(pathFragment);
|
|
4845
5100
|
}
|
|
4846
5101
|
}
|
|
4847
5102
|
}
|
|
4848
5103
|
}
|
|
4849
5104
|
if (requiresContentConfig) {
|
|
4850
|
-
if (!
|
|
5105
|
+
if (!existsSync8(join11(cwd, "src/content/config.ts"))) {
|
|
4851
5106
|
reportError("Missing expected file: src/content/config.ts");
|
|
4852
5107
|
}
|
|
4853
5108
|
}
|
|
@@ -4938,19 +5193,19 @@ async function listBlocksHandler(args2) {
|
|
|
4938
5193
|
}
|
|
4939
5194
|
|
|
4940
5195
|
// src/mcp/tools/add-block.ts
|
|
4941
|
-
import { readFileSync as
|
|
4942
|
-
import { join as
|
|
5196
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
5197
|
+
import { join as join12, dirname as dirname5 } from "path";
|
|
4943
5198
|
async function addBlock2(input) {
|
|
4944
5199
|
const { name, variant = "default", projectDirectory } = input;
|
|
4945
|
-
const manifestPath =
|
|
4946
|
-
if (!
|
|
5200
|
+
const manifestPath = join12(projectDirectory, "fornix.json");
|
|
5201
|
+
if (!existsSync9(manifestPath)) {
|
|
4947
5202
|
return err(
|
|
4948
5203
|
new Error("No fornix.json found. Not a Fornix project directory.")
|
|
4949
5204
|
);
|
|
4950
5205
|
}
|
|
4951
5206
|
let manifest2;
|
|
4952
5207
|
try {
|
|
4953
|
-
const raw =
|
|
5208
|
+
const raw = readFileSync10(manifestPath, "utf-8");
|
|
4954
5209
|
manifest2 = JSON.parse(raw);
|
|
4955
5210
|
} catch {
|
|
4956
5211
|
return err(new Error("Failed to parse fornix.json."));
|
|
@@ -5002,7 +5257,7 @@ async function addBlock2(input) {
|
|
|
5002
5257
|
)
|
|
5003
5258
|
);
|
|
5004
5259
|
}
|
|
5005
|
-
const filePath =
|
|
5260
|
+
const filePath = join12(projectDirectory, file.destination);
|
|
5006
5261
|
mkdirSync6(dirname5(filePath), { recursive: true });
|
|
5007
5262
|
writeFileSync7(filePath, content);
|
|
5008
5263
|
filesCreated++;
|
|
@@ -5041,25 +5296,25 @@ function resolveDependencies3(blockName, installedNames, manifests) {
|
|
|
5041
5296
|
|
|
5042
5297
|
// src/mcp/tools/remove-block.ts
|
|
5043
5298
|
import {
|
|
5044
|
-
readFileSync as
|
|
5299
|
+
readFileSync as readFileSync11,
|
|
5045
5300
|
writeFileSync as writeFileSync8,
|
|
5046
|
-
existsSync as
|
|
5301
|
+
existsSync as existsSync10,
|
|
5047
5302
|
unlinkSync as unlinkSync2,
|
|
5048
5303
|
readdirSync as readdirSync4,
|
|
5049
5304
|
rmdirSync as rmdirSync2
|
|
5050
5305
|
} from "fs";
|
|
5051
|
-
import { join as
|
|
5306
|
+
import { join as join13, dirname as dirname6 } from "path";
|
|
5052
5307
|
async function removeBlock(input) {
|
|
5053
5308
|
const { name, force = false, projectDirectory } = input;
|
|
5054
|
-
const manifestPath =
|
|
5055
|
-
if (!
|
|
5309
|
+
const manifestPath = join13(projectDirectory, "fornix.json");
|
|
5310
|
+
if (!existsSync10(manifestPath)) {
|
|
5056
5311
|
return err(
|
|
5057
5312
|
new Error("No fornix.json found. Not a Fornix project directory.")
|
|
5058
5313
|
);
|
|
5059
5314
|
}
|
|
5060
5315
|
let manifest2;
|
|
5061
5316
|
try {
|
|
5062
|
-
const raw =
|
|
5317
|
+
const raw = readFileSync11(manifestPath, "utf-8");
|
|
5063
5318
|
manifest2 = JSON.parse(raw);
|
|
5064
5319
|
} catch {
|
|
5065
5320
|
return err(new Error("Failed to parse fornix.json."));
|
|
@@ -5085,8 +5340,8 @@ async function removeBlock(input) {
|
|
|
5085
5340
|
const filesToRemove = [];
|
|
5086
5341
|
if (blockManifest) {
|
|
5087
5342
|
for (const file of blockManifest.files) {
|
|
5088
|
-
const filePath =
|
|
5089
|
-
if (
|
|
5343
|
+
const filePath = join13(projectDirectory, file.destination);
|
|
5344
|
+
if (existsSync10(filePath)) {
|
|
5090
5345
|
filesToRemove.push(filePath);
|
|
5091
5346
|
}
|
|
5092
5347
|
}
|
|
@@ -5218,17 +5473,17 @@ function zodTypeForSlot(slotType) {
|
|
|
5218
5473
|
}
|
|
5219
5474
|
|
|
5220
5475
|
// src/mcp/tools/get-project-status.ts
|
|
5221
|
-
import { readFileSync as
|
|
5222
|
-
import { join as
|
|
5476
|
+
import { readFileSync as readFileSync12, existsSync as existsSync11 } from "fs";
|
|
5477
|
+
import { join as join14 } from "path";
|
|
5223
5478
|
function getProjectStatus(input) {
|
|
5224
|
-
const manifestPath =
|
|
5225
|
-
if (!
|
|
5479
|
+
const manifestPath = join14(input.projectDirectory, "fornix.json");
|
|
5480
|
+
if (!existsSync11(manifestPath)) {
|
|
5226
5481
|
return err(
|
|
5227
5482
|
new Error("No fornix.json found. Not a Fornix project directory.")
|
|
5228
5483
|
);
|
|
5229
5484
|
}
|
|
5230
5485
|
try {
|
|
5231
|
-
const raw =
|
|
5486
|
+
const raw = readFileSync12(manifestPath, "utf-8");
|
|
5232
5487
|
const manifest2 = JSON.parse(raw);
|
|
5233
5488
|
const blocks = manifest2.blocks;
|
|
5234
5489
|
return ok({
|
|
@@ -5251,7 +5506,7 @@ function getProjectStatus(input) {
|
|
|
5251
5506
|
|
|
5252
5507
|
// src/mcp/tools/scaffold-project.ts
|
|
5253
5508
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync9 } from "fs";
|
|
5254
|
-
import { join as
|
|
5509
|
+
import { join as join15, basename as basename3 } from "path";
|
|
5255
5510
|
var DEFAULT_COLORS2 = {
|
|
5256
5511
|
primary: "#6366f1",
|
|
5257
5512
|
secondary: "#818cf8",
|
|
@@ -5322,8 +5577,8 @@ async function scaffoldProject(input) {
|
|
|
5322
5577
|
const files = result.value.files;
|
|
5323
5578
|
let filesCreated = 0;
|
|
5324
5579
|
for (const [relativePath, content] of Object.entries(files)) {
|
|
5325
|
-
const fullPath =
|
|
5326
|
-
const parentDirectory =
|
|
5580
|
+
const fullPath = join15(projectDirectory, relativePath);
|
|
5581
|
+
const parentDirectory = join15(fullPath, "..");
|
|
5327
5582
|
mkdirSync7(parentDirectory, { recursive: true });
|
|
5328
5583
|
writeFileSync9(fullPath, content, "utf-8");
|
|
5329
5584
|
filesCreated++;
|