pabal-resource-mcp 1.8.10 → 1.8.12
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/bin/mcp-server.js +61 -154
- package/package.json +1 -1
package/dist/bin/mcp-server.js
CHANGED
|
@@ -5126,9 +5126,9 @@ Expected phone screenshots in: ${screenshotsDir2}/{locale}/phone/`
|
|
|
5126
5126
|
// src/tools/app-icon/generate-app-icons.ts
|
|
5127
5127
|
import { z as z10 } from "zod";
|
|
5128
5128
|
import { zodToJsonSchema as zodToJsonSchema10 } from "zod-to-json-schema";
|
|
5129
|
-
import
|
|
5130
|
-
import
|
|
5131
|
-
import
|
|
5129
|
+
import fs15 from "fs";
|
|
5130
|
+
import path15 from "path";
|
|
5131
|
+
import sharp5 from "sharp";
|
|
5132
5132
|
|
|
5133
5133
|
// src/tools/app-icon/utils/icon-specs.util.ts
|
|
5134
5134
|
import path14 from "path";
|
|
@@ -5263,14 +5263,12 @@ async function trimIconPadding(inputPath, threshold = 10) {
|
|
|
5263
5263
|
const trimmed = await sharp4(inputPath).trim({ threshold }).toBuffer();
|
|
5264
5264
|
return trimmed;
|
|
5265
5265
|
}
|
|
5266
|
-
async function convertToWhiteMask(inputPath
|
|
5267
|
-
const
|
|
5268
|
-
const { data, info } = await sharp4(grayscale).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
5266
|
+
async function convertToWhiteMask(inputPath) {
|
|
5267
|
+
const { data, info } = await sharp4(inputPath).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
5269
5268
|
const pixels = new Uint8Array(data.length);
|
|
5270
5269
|
for (let i = 0; i < data.length; i += 4) {
|
|
5271
|
-
const gray = data[i];
|
|
5272
5270
|
const alpha = data[i + 3];
|
|
5273
|
-
if (alpha > 10
|
|
5271
|
+
if (alpha > 10) {
|
|
5274
5272
|
pixels[i] = 255;
|
|
5275
5273
|
pixels[i + 1] = 255;
|
|
5276
5274
|
pixels[i + 2] = 255;
|
|
@@ -5282,14 +5280,13 @@ async function convertToWhiteMask(inputPath, threshold = 128) {
|
|
|
5282
5280
|
pixels[i + 3] = 0;
|
|
5283
5281
|
}
|
|
5284
5282
|
}
|
|
5285
|
-
|
|
5283
|
+
return sharp4(pixels, {
|
|
5286
5284
|
raw: {
|
|
5287
5285
|
width: info.width,
|
|
5288
5286
|
height: info.height,
|
|
5289
5287
|
channels: 4
|
|
5290
5288
|
}
|
|
5291
5289
|
}).png().toBuffer();
|
|
5292
|
-
return whiteMask;
|
|
5293
5290
|
}
|
|
5294
5291
|
function calculateAlignmentArea(canvasSize, safeZoneLeft, safeZoneRight, safeZoneTop, safeZoneBottom, alignment) {
|
|
5295
5292
|
const safeZoneDiameter = safeZoneRight - safeZoneLeft;
|
|
@@ -5400,56 +5397,6 @@ function calculateFinalPosition(areaLeft, areaTop, areaWidth, areaHeight, logoWi
|
|
|
5400
5397
|
return { left, top };
|
|
5401
5398
|
}
|
|
5402
5399
|
|
|
5403
|
-
// src/tools/app-icon/utils/icon-masking.util.ts
|
|
5404
|
-
import fs15 from "fs";
|
|
5405
|
-
import path15 from "path";
|
|
5406
|
-
import sharp5 from "sharp";
|
|
5407
|
-
async function applyWhiteMasking(inputPath, outputPath, targetSize) {
|
|
5408
|
-
try {
|
|
5409
|
-
const outputDir = path15.dirname(outputPath);
|
|
5410
|
-
if (!fs15.existsSync(outputDir)) {
|
|
5411
|
-
fs15.mkdirSync(outputDir, { recursive: true });
|
|
5412
|
-
}
|
|
5413
|
-
const processedBuffer = await createWhiteMaskFromOriginal(inputPath);
|
|
5414
|
-
await sharp5(processedBuffer).resize(targetSize, targetSize, {
|
|
5415
|
-
fit: "contain",
|
|
5416
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
5417
|
-
}).png().toFile(outputPath);
|
|
5418
|
-
return { success: true };
|
|
5419
|
-
} catch (error) {
|
|
5420
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5421
|
-
return {
|
|
5422
|
-
success: false,
|
|
5423
|
-
error: message
|
|
5424
|
-
};
|
|
5425
|
-
}
|
|
5426
|
-
}
|
|
5427
|
-
async function createWhiteMaskFromOriginal(inputPath) {
|
|
5428
|
-
const { data, info } = await sharp5(inputPath).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
5429
|
-
const pixels = new Uint8Array(data.length);
|
|
5430
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
5431
|
-
const a = data[i + 3];
|
|
5432
|
-
if (a > 10) {
|
|
5433
|
-
pixels[i] = 255;
|
|
5434
|
-
pixels[i + 1] = 255;
|
|
5435
|
-
pixels[i + 2] = 255;
|
|
5436
|
-
pixels[i + 3] = 255;
|
|
5437
|
-
} else {
|
|
5438
|
-
pixels[i] = 0;
|
|
5439
|
-
pixels[i + 1] = 0;
|
|
5440
|
-
pixels[i + 2] = 0;
|
|
5441
|
-
pixels[i + 3] = 0;
|
|
5442
|
-
}
|
|
5443
|
-
}
|
|
5444
|
-
return sharp5(pixels, {
|
|
5445
|
-
raw: {
|
|
5446
|
-
width: info.width,
|
|
5447
|
-
height: info.height,
|
|
5448
|
-
channels: 4
|
|
5449
|
-
}
|
|
5450
|
-
}).png().toBuffer();
|
|
5451
|
-
}
|
|
5452
|
-
|
|
5453
5400
|
// src/tools/app-icon/generate-app-icons.ts
|
|
5454
5401
|
var TOOL_NAME6 = "generate-app-icons";
|
|
5455
5402
|
var generateAppIconsInputSchema = z10.object({
|
|
@@ -5485,9 +5432,6 @@ var generateAppIconsInputSchema = z10.object({
|
|
|
5485
5432
|
]).optional().describe(
|
|
5486
5433
|
"Logo alignment within the canvas (default: center or config default). Affects how the logo is positioned relative to the safe zone."
|
|
5487
5434
|
),
|
|
5488
|
-
useAlphaMasking: z10.boolean().optional().default(false).describe(
|
|
5489
|
-
"Use alpha channel for white masking (default: false). When false, uses Sharp-based threshold conversion (converts bright pixels to white). When true, uses original image's alpha channel (preserves exact logo shape)."
|
|
5490
|
-
),
|
|
5491
5435
|
skipExisting: z10.boolean().optional().default(false).describe("Skip generation if output file already exists (default: false)"),
|
|
5492
5436
|
dryRun: z10.boolean().optional().default(false).describe(
|
|
5493
5437
|
"Preview mode - shows what would be generated without actually generating"
|
|
@@ -5520,16 +5464,6 @@ var generateAppIconsTool = {
|
|
|
5520
5464
|
- **Style Variants**: Generate themed icons (christmas, halloween, etc.) with style-specific defaults
|
|
5521
5465
|
- **Config Integration**: Uses config.json appIcon settings for default colors and alignment
|
|
5522
5466
|
|
|
5523
|
-
**White Masking Options:**
|
|
5524
|
-
- **Default (useAlphaMasking=false)**: Threshold conversion - converts bright pixels to white
|
|
5525
|
-
- **Alpha-based (useAlphaMasking=true)**: Uses original alpha channel - preserves exact logo shape
|
|
5526
|
-
|
|
5527
|
-
**\u26A0\uFE0F Important: After Generation**
|
|
5528
|
-
After generating icons, always check **android-notification-icon.png**:
|
|
5529
|
-
- If white masking is not clean (unwanted artifacts or shape issues)
|
|
5530
|
-
- Regenerate with \`useAlphaMasking: true\` for alpha-based masking
|
|
5531
|
-
- Example: \`{ "appName": "my-app", "useAlphaMasking": true, "iconTypes": ["android-notification-icon"] }\`
|
|
5532
|
-
|
|
5533
5467
|
**Example:**
|
|
5534
5468
|
\`\`\`
|
|
5535
5469
|
INPUT: my-app/icons/icon.png (source logo with padding)
|
|
@@ -5555,11 +5489,11 @@ function validateApp4(appName) {
|
|
|
5555
5489
|
);
|
|
5556
5490
|
}
|
|
5557
5491
|
const productsDir = getProductsDir();
|
|
5558
|
-
const configPath =
|
|
5492
|
+
const configPath = path15.join(productsDir, app.slug, "config.json");
|
|
5559
5493
|
let config;
|
|
5560
|
-
if (
|
|
5494
|
+
if (fs15.existsSync(configPath)) {
|
|
5561
5495
|
try {
|
|
5562
|
-
const configData =
|
|
5496
|
+
const configData = fs15.readFileSync(configPath, "utf-8");
|
|
5563
5497
|
config = JSON.parse(configData);
|
|
5564
5498
|
} catch (error) {
|
|
5565
5499
|
console.warn(
|
|
@@ -5578,7 +5512,7 @@ function buildGenerationTasks(slug, iconTypes, skipExisting, styleFolder) {
|
|
|
5578
5512
|
const tasks = [];
|
|
5579
5513
|
const baseIconPath = getBaseIconPath(slug, styleFolder);
|
|
5580
5514
|
const iconsDir = getIconsDir(slug, styleFolder);
|
|
5581
|
-
if (!
|
|
5515
|
+
if (!fs15.existsSync(baseIconPath)) {
|
|
5582
5516
|
throw new Error(
|
|
5583
5517
|
`Base icon not found: ${baseIconPath}
|
|
5584
5518
|
|
|
@@ -5587,7 +5521,7 @@ Please place your base icon at this location first.`
|
|
|
5587
5521
|
}
|
|
5588
5522
|
for (const iconType of iconTypes) {
|
|
5589
5523
|
const outputPath = getIconOutputPath(slug, iconType, styleFolder);
|
|
5590
|
-
if (skipExisting &&
|
|
5524
|
+
if (skipExisting && fs15.existsSync(outputPath)) {
|
|
5591
5525
|
continue;
|
|
5592
5526
|
}
|
|
5593
5527
|
tasks.push({
|
|
@@ -5599,7 +5533,7 @@ Please place your base icon at this location first.`
|
|
|
5599
5533
|
}
|
|
5600
5534
|
return { tasks, baseIconPath };
|
|
5601
5535
|
}
|
|
5602
|
-
async function generateIcons(tasks, backgroundColor, logoAlignment,
|
|
5536
|
+
async function generateIcons(tasks, backgroundColor, logoAlignment, onProgress) {
|
|
5603
5537
|
let generatedCount = 0;
|
|
5604
5538
|
const errors = [];
|
|
5605
5539
|
const total = tasks.length;
|
|
@@ -5613,27 +5547,16 @@ async function generateIcons(tasks, backgroundColor, logoAlignment, useAlphaMask
|
|
|
5613
5547
|
};
|
|
5614
5548
|
onProgress?.(progress);
|
|
5615
5549
|
try {
|
|
5616
|
-
const outputDir =
|
|
5617
|
-
if (!
|
|
5618
|
-
|
|
5550
|
+
const outputDir = path15.dirname(task.outputPath);
|
|
5551
|
+
if (!fs15.existsSync(outputDir)) {
|
|
5552
|
+
fs15.mkdirSync(outputDir, { recursive: true });
|
|
5619
5553
|
}
|
|
5620
5554
|
if (task.iconType === "android-notification-icon") {
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
);
|
|
5627
|
-
if (!result.success) {
|
|
5628
|
-
throw new Error(result.error || "AI white masking failed");
|
|
5629
|
-
}
|
|
5630
|
-
} else {
|
|
5631
|
-
const whiteMask = await convertToWhiteMask(task.inputPath);
|
|
5632
|
-
await sharp6(whiteMask).resize(task.spec.size, task.spec.size, {
|
|
5633
|
-
fit: "contain",
|
|
5634
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
5635
|
-
}).png().toFile(task.outputPath);
|
|
5636
|
-
}
|
|
5555
|
+
const whiteMask = await convertToWhiteMask(task.inputPath);
|
|
5556
|
+
await sharp5(whiteMask).resize(task.spec.size, task.spec.size, {
|
|
5557
|
+
fit: "contain",
|
|
5558
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
5559
|
+
}).png().toFile(task.outputPath);
|
|
5637
5560
|
} else {
|
|
5638
5561
|
const iconBgColor = task.iconType === "ios-light" ? backgroundColor : "transparent";
|
|
5639
5562
|
await resizeIconWithSafeZone(
|
|
@@ -5667,7 +5590,6 @@ async function handleGenerateAppIcons(input) {
|
|
|
5667
5590
|
styleFolder,
|
|
5668
5591
|
backgroundColor: bgColorInput,
|
|
5669
5592
|
logoAlignment: logoAlignmentInput,
|
|
5670
|
-
useAlphaMasking = false,
|
|
5671
5593
|
skipExisting = false,
|
|
5672
5594
|
dryRun = false
|
|
5673
5595
|
} = input;
|
|
@@ -5715,11 +5637,6 @@ async function handleGenerateAppIcons(input) {
|
|
|
5715
5637
|
const iconTypes = requestedIconTypes || ALL_ICON_TYPES;
|
|
5716
5638
|
results.push(`\u{1F3AF} Icon types: ${iconTypes.join(", ")}`);
|
|
5717
5639
|
results.push(`\u{1F4D0} Logo alignment: ${logoAlignment}`);
|
|
5718
|
-
if (useAlphaMasking) {
|
|
5719
|
-
results.push(`\u{1F3AD} White masking: alpha-based (preserves exact shape)`);
|
|
5720
|
-
} else {
|
|
5721
|
-
results.push(`\u{1F3AD} White masking: threshold-based (converts bright pixels)`);
|
|
5722
|
-
}
|
|
5723
5640
|
let tasks;
|
|
5724
5641
|
let baseIconPath;
|
|
5725
5642
|
try {
|
|
@@ -5787,7 +5704,6 @@ async function handleGenerateAppIcons(input) {
|
|
|
5787
5704
|
tasks,
|
|
5788
5705
|
bgColor,
|
|
5789
5706
|
logoAlignment,
|
|
5790
|
-
useAlphaMasking,
|
|
5791
5707
|
(progress) => {
|
|
5792
5708
|
const progressPrefix = `[${progress.current}/${progress.total}]`;
|
|
5793
5709
|
if (progress.status === "generating") {
|
|
@@ -5819,21 +5735,6 @@ async function handleGenerateAppIcons(input) {
|
|
|
5819
5735
|
\u{1F4C1} Output location: ${iconsDir}/`);
|
|
5820
5736
|
results.push(`
|
|
5821
5737
|
\u2705 Icon generation complete!`);
|
|
5822
|
-
const hasNotificationIcon = tasks.some((t) => t.iconType === "android-notification-icon") && !generationResult.errors.some(
|
|
5823
|
-
(e) => e.iconType === "android-notification-icon"
|
|
5824
|
-
);
|
|
5825
|
-
if (hasNotificationIcon && !useAlphaMasking) {
|
|
5826
|
-
results.push(
|
|
5827
|
-
`
|
|
5828
|
-
\u26A0\uFE0F IMPORTANT: Check android-notification-icon.png`
|
|
5829
|
-
);
|
|
5830
|
-
results.push(
|
|
5831
|
-
` If the shape is not correct, regenerate with alpha masking:`
|
|
5832
|
-
);
|
|
5833
|
-
results.push(
|
|
5834
|
-
` { "appName": "${appInfo.slug}", "useAlphaMasking": true, "iconTypes": ["android-notification-icon"]${styleFolder ? `, "styleFolder": "${styleFolder}"` : ""} }`
|
|
5835
|
-
);
|
|
5836
|
-
}
|
|
5837
5738
|
return {
|
|
5838
5739
|
content: [
|
|
5839
5740
|
{
|
|
@@ -5847,22 +5748,22 @@ async function handleGenerateAppIcons(input) {
|
|
|
5847
5748
|
// src/tools/app-icon/stylize-app-icon.ts
|
|
5848
5749
|
import { z as z11 } from "zod";
|
|
5849
5750
|
import { zodToJsonSchema as zodToJsonSchema11 } from "zod-to-json-schema";
|
|
5850
|
-
import fs18 from "fs";
|
|
5851
|
-
import path18 from "path";
|
|
5852
|
-
import sharp7 from "sharp";
|
|
5853
|
-
|
|
5854
|
-
// src/tools/app-icon/utils/gemini.util.ts
|
|
5855
5751
|
import fs17 from "fs";
|
|
5856
5752
|
import path17 from "path";
|
|
5753
|
+
import sharp6 from "sharp";
|
|
5754
|
+
|
|
5755
|
+
// src/tools/app-icon/utils/gemini.util.ts
|
|
5756
|
+
import fs16 from "fs";
|
|
5757
|
+
import path16 from "path";
|
|
5857
5758
|
import { GoogleGenAI as GoogleGenAI3 } from "@google/genai";
|
|
5858
5759
|
function getGeminiClient3() {
|
|
5859
5760
|
const apiKey = getGeminiApiKey();
|
|
5860
5761
|
return new GoogleGenAI3({ apiKey });
|
|
5861
5762
|
}
|
|
5862
5763
|
function readImageAsBase643(imagePath) {
|
|
5863
|
-
const buffer =
|
|
5764
|
+
const buffer = fs16.readFileSync(imagePath);
|
|
5864
5765
|
const base64 = buffer.toString("base64");
|
|
5865
|
-
const ext =
|
|
5766
|
+
const ext = path16.extname(imagePath).toLowerCase();
|
|
5866
5767
|
let mimeType = "image/png";
|
|
5867
5768
|
if (ext === ".jpg" || ext === ".jpeg") {
|
|
5868
5769
|
mimeType = "image/jpeg";
|
|
@@ -6006,12 +5907,12 @@ Generate the stylized icon with transparent background now.`;
|
|
|
6006
5907
|
for (const part of parts) {
|
|
6007
5908
|
if (part.inlineData?.data) {
|
|
6008
5909
|
const imageBuffer = Buffer.from(part.inlineData.data, "base64");
|
|
6009
|
-
const outputDir =
|
|
6010
|
-
if (!
|
|
6011
|
-
|
|
5910
|
+
const outputDir = path17.dirname(outputPath);
|
|
5911
|
+
if (!fs17.existsSync(outputDir)) {
|
|
5912
|
+
fs17.mkdirSync(outputDir, { recursive: true });
|
|
6012
5913
|
}
|
|
6013
|
-
const processedImage = await
|
|
6014
|
-
await
|
|
5914
|
+
const processedImage = await sharp6(imageBuffer).ensureAlpha().png().toBuffer();
|
|
5915
|
+
await sharp6(processedImage).toFile(outputPath);
|
|
6015
5916
|
return { success: true };
|
|
6016
5917
|
}
|
|
6017
5918
|
}
|
|
@@ -6051,7 +5952,7 @@ async function handleStylizeAppIcon(input) {
|
|
|
6051
5952
|
};
|
|
6052
5953
|
}
|
|
6053
5954
|
const baseIconPath = getBaseIconPath(appInfo.slug);
|
|
6054
|
-
if (!
|
|
5955
|
+
if (!fs17.existsSync(baseIconPath)) {
|
|
6055
5956
|
return {
|
|
6056
5957
|
content: [
|
|
6057
5958
|
{
|
|
@@ -6145,13 +6046,13 @@ Next step: Run generate-app-icons with styleFolder='${styleFolder}' to create pl
|
|
|
6145
6046
|
}
|
|
6146
6047
|
|
|
6147
6048
|
// src/tools/apps/init.ts
|
|
6148
|
-
import
|
|
6149
|
-
import
|
|
6049
|
+
import fs18 from "fs";
|
|
6050
|
+
import path18 from "path";
|
|
6150
6051
|
import { z as z12 } from "zod";
|
|
6151
6052
|
import { zodToJsonSchema as zodToJsonSchema12 } from "zod-to-json-schema";
|
|
6152
6053
|
var listSlugDirs = (dir) => {
|
|
6153
|
-
if (!
|
|
6154
|
-
return
|
|
6054
|
+
if (!fs18.existsSync(dir)) return [];
|
|
6055
|
+
return fs18.readdirSync(dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
6155
6056
|
};
|
|
6156
6057
|
var initProjectInputSchema = z12.object({
|
|
6157
6058
|
slug: z12.string().trim().optional().describe(
|
|
@@ -6176,7 +6077,7 @@ Steps:
|
|
|
6176
6077
|
inputSchema: inputSchema12
|
|
6177
6078
|
};
|
|
6178
6079
|
async function handleInitProject(input) {
|
|
6179
|
-
const pullDataDir =
|
|
6080
|
+
const pullDataDir = path18.join(getPullDataDir(), "products");
|
|
6180
6081
|
const publicDir = getProductsDir();
|
|
6181
6082
|
const pullDataSlugs = listSlugDirs(pullDataDir);
|
|
6182
6083
|
const publicSlugs = listSlugDirs(publicDir);
|
|
@@ -6259,14 +6160,14 @@ async function handleInitProject(input) {
|
|
|
6259
6160
|
}
|
|
6260
6161
|
|
|
6261
6162
|
// src/tools/content/create-blog-html.ts
|
|
6262
|
-
import
|
|
6263
|
-
import
|
|
6163
|
+
import fs20 from "fs";
|
|
6164
|
+
import path20 from "path";
|
|
6264
6165
|
import { z as z13 } from "zod";
|
|
6265
6166
|
import { zodToJsonSchema as zodToJsonSchema13 } from "zod-to-json-schema";
|
|
6266
6167
|
|
|
6267
6168
|
// src/utils/blog.util.ts
|
|
6268
|
-
import
|
|
6269
|
-
import
|
|
6169
|
+
import fs19 from "fs";
|
|
6170
|
+
import path19 from "path";
|
|
6270
6171
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
6271
6172
|
var BLOG_ROOT = "blogs";
|
|
6272
6173
|
var removeDiacritics = (value) => value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
|
|
@@ -6354,13 +6255,13 @@ function resolveTargetLocales(input) {
|
|
|
6354
6255
|
return fallback ? [fallback] : [];
|
|
6355
6256
|
}
|
|
6356
6257
|
function getBlogOutputPaths(options) {
|
|
6357
|
-
const baseDir =
|
|
6258
|
+
const baseDir = path19.join(
|
|
6358
6259
|
options.publicDir,
|
|
6359
6260
|
BLOG_ROOT,
|
|
6360
6261
|
options.appSlug,
|
|
6361
6262
|
options.slug
|
|
6362
6263
|
);
|
|
6363
|
-
const filePath =
|
|
6264
|
+
const filePath = path19.join(baseDir, `${options.locale}.html`);
|
|
6364
6265
|
const publicBasePath = toPublicBlogBase(options.appSlug, options.slug);
|
|
6365
6266
|
return { baseDir, filePath, publicBasePath };
|
|
6366
6267
|
}
|
|
@@ -6385,18 +6286,18 @@ function findExistingBlogPosts({
|
|
|
6385
6286
|
publicDir,
|
|
6386
6287
|
limit = 2
|
|
6387
6288
|
}) {
|
|
6388
|
-
const blogAppDir =
|
|
6389
|
-
if (!
|
|
6289
|
+
const blogAppDir = path19.join(publicDir, BLOG_ROOT, appSlug);
|
|
6290
|
+
if (!fs19.existsSync(blogAppDir)) {
|
|
6390
6291
|
return [];
|
|
6391
6292
|
}
|
|
6392
6293
|
const posts = [];
|
|
6393
|
-
const subdirs =
|
|
6294
|
+
const subdirs = fs19.readdirSync(blogAppDir, { withFileTypes: true });
|
|
6394
6295
|
for (const subdir of subdirs) {
|
|
6395
6296
|
if (!subdir.isDirectory()) continue;
|
|
6396
|
-
const localeFile =
|
|
6397
|
-
if (!
|
|
6297
|
+
const localeFile = path19.join(blogAppDir, subdir.name, `${locale}.html`);
|
|
6298
|
+
if (!fs19.existsSync(localeFile)) continue;
|
|
6398
6299
|
try {
|
|
6399
|
-
const htmlContent =
|
|
6300
|
+
const htmlContent = fs19.readFileSync(localeFile, "utf-8");
|
|
6400
6301
|
const { meta, body } = parseBlogHtml(htmlContent);
|
|
6401
6302
|
if (meta && meta.locale === locale) {
|
|
6402
6303
|
posts.push({
|
|
@@ -6539,7 +6440,7 @@ async function handleCreateBlogHtml(input) {
|
|
|
6539
6440
|
}
|
|
6540
6441
|
const output = {
|
|
6541
6442
|
slug,
|
|
6542
|
-
baseDir:
|
|
6443
|
+
baseDir: path20.join(publicDir, "blogs", appSlug, slug),
|
|
6543
6444
|
files: [],
|
|
6544
6445
|
coverImage: coverImage && coverImage.trim().length > 0 ? coverImage.trim() : `/products/${appSlug}/og-image.png`,
|
|
6545
6446
|
metaByLocale: {}
|
|
@@ -6553,7 +6454,7 @@ async function handleCreateBlogHtml(input) {
|
|
|
6553
6454
|
})
|
|
6554
6455
|
);
|
|
6555
6456
|
const existing = plannedFiles.filter(
|
|
6556
|
-
({ filePath }) =>
|
|
6457
|
+
({ filePath }) => fs20.existsSync(filePath)
|
|
6557
6458
|
);
|
|
6558
6459
|
if (existing.length > 0 && !overwrite) {
|
|
6559
6460
|
const existingList = existing.map((f) => f.filePath).join("\n- ");
|
|
@@ -6562,7 +6463,7 @@ async function handleCreateBlogHtml(input) {
|
|
|
6562
6463
|
- ${existingList}`
|
|
6563
6464
|
);
|
|
6564
6465
|
}
|
|
6565
|
-
|
|
6466
|
+
fs20.mkdirSync(output.baseDir, { recursive: true });
|
|
6566
6467
|
for (const locale of targetLocales) {
|
|
6567
6468
|
const { filePath } = getBlogOutputPaths({
|
|
6568
6469
|
appSlug,
|
|
@@ -6588,7 +6489,7 @@ async function handleCreateBlogHtml(input) {
|
|
|
6588
6489
|
meta,
|
|
6589
6490
|
content
|
|
6590
6491
|
});
|
|
6591
|
-
|
|
6492
|
+
fs20.writeFileSync(filePath, html, "utf-8");
|
|
6592
6493
|
output.files.push({ locale, path: filePath });
|
|
6593
6494
|
}
|
|
6594
6495
|
const summaryLines = [
|
|
@@ -6769,6 +6670,12 @@ function getToolZodSchema(name) {
|
|
|
6769
6670
|
}
|
|
6770
6671
|
|
|
6771
6672
|
// src/bin/mcp-server.ts
|
|
6673
|
+
console.log = function(...args) {
|
|
6674
|
+
console.error(...args);
|
|
6675
|
+
};
|
|
6676
|
+
console.info = function(...args) {
|
|
6677
|
+
console.error(...args);
|
|
6678
|
+
};
|
|
6772
6679
|
var server = new Server(
|
|
6773
6680
|
{
|
|
6774
6681
|
name: "pabal-resource-mcp",
|