pabal-resource-mcp 1.8.9 → 1.8.11

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.
@@ -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 fs17 from "fs";
5130
- import path17 from "path";
5131
- import sharp6 from "sharp";
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, threshold = 128) {
5267
- const grayscale = await sharp4(inputPath).greyscale().toBuffer();
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 && gray > threshold) {
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
- const whiteMask = await sharp4(pixels, {
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,136 +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 fs16 from "fs";
5405
- import path16 from "path";
5406
- import sharp5 from "sharp";
5407
-
5408
- // src/tools/app-icon/utils/gemini.util.ts
5409
- import fs15 from "fs";
5410
- import path15 from "path";
5411
- import { GoogleGenAI as GoogleGenAI3 } from "@google/genai";
5412
- function getGeminiClient3() {
5413
- const apiKey = getGeminiApiKey();
5414
- return new GoogleGenAI3({ apiKey });
5415
- }
5416
- function readImageAsBase643(imagePath) {
5417
- const buffer = fs15.readFileSync(imagePath);
5418
- const base64 = buffer.toString("base64");
5419
- const ext = path15.extname(imagePath).toLowerCase();
5420
- let mimeType = "image/png";
5421
- if (ext === ".jpg" || ext === ".jpeg") {
5422
- mimeType = "image/jpeg";
5423
- } else if (ext === ".webp") {
5424
- mimeType = "image/webp";
5425
- }
5426
- return { data: base64, mimeType };
5427
- }
5428
-
5429
- // src/tools/app-icon/utils/icon-masking.util.ts
5430
- async function applyWhiteMasking(inputPath, outputPath, targetSize, logoPosition) {
5431
- try {
5432
- const client = getGeminiClient3();
5433
- const { data: imageData, mimeType } = readImageAsBase643(inputPath);
5434
- const positionInstruction = logoPosition ? `
5435
- - Logo positioning hint: ${logoPosition}` : "";
5436
- const prompt = `Convert this icon into a simple white Android notification icon.
5437
-
5438
- Requirements:
5439
- - White logo (#FFFFFF) on transparent background
5440
- - Preserve the logo shape exactly
5441
- - No gradients, solid white only${positionInstruction}`;
5442
- const chat = client.chats.create({
5443
- model: "gemini-3-pro-image-preview",
5444
- config: {
5445
- responseModalities: ["TEXT", "IMAGE"]
5446
- }
5447
- });
5448
- const response = await chat.sendMessage({
5449
- message: [
5450
- { text: prompt },
5451
- {
5452
- inlineData: {
5453
- mimeType,
5454
- data: imageData
5455
- }
5456
- }
5457
- ],
5458
- config: {
5459
- responseModalities: ["TEXT", "IMAGE"]
5460
- }
5461
- });
5462
- const candidates = response.candidates;
5463
- if (!candidates || candidates.length === 0) {
5464
- return {
5465
- success: false,
5466
- error: "No response from Gemini API"
5467
- };
5468
- }
5469
- const parts = candidates[0].content?.parts;
5470
- if (!parts) {
5471
- return {
5472
- success: false,
5473
- error: "No content parts in response"
5474
- };
5475
- }
5476
- for (const part of parts) {
5477
- if (part.inlineData?.data) {
5478
- const imageBuffer = Buffer.from(part.inlineData.data, "base64");
5479
- const outputDir = path16.dirname(outputPath);
5480
- if (!fs16.existsSync(outputDir)) {
5481
- fs16.mkdirSync(outputDir, { recursive: true });
5482
- }
5483
- const processedBuffer = await ensureTransparentBackground(imageBuffer);
5484
- await sharp5(processedBuffer).resize(targetSize, targetSize, {
5485
- fit: "contain",
5486
- background: { r: 0, g: 0, b: 0, alpha: 0 }
5487
- }).png().toFile(outputPath);
5488
- return { success: true };
5489
- }
5490
- }
5491
- return {
5492
- success: false,
5493
- error: "No image data in Gemini response"
5494
- };
5495
- } catch (error) {
5496
- const message = error instanceof Error ? error.message : String(error);
5497
- return {
5498
- success: false,
5499
- error: message
5500
- };
5501
- }
5502
- }
5503
- async function ensureTransparentBackground(imageBuffer) {
5504
- const { data, info } = await sharp5(imageBuffer).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
5505
- const pixels = new Uint8Array(data.length);
5506
- for (let i = 0; i < data.length; i += 4) {
5507
- const r = data[i];
5508
- const g = data[i + 1];
5509
- const b = data[i + 2];
5510
- const a = data[i + 3];
5511
- const brightness = (r + g + b) / 3;
5512
- if (brightness > 200 && a > 10) {
5513
- pixels[i] = 255;
5514
- pixels[i + 1] = 255;
5515
- pixels[i + 2] = 255;
5516
- pixels[i + 3] = 255;
5517
- } else {
5518
- pixels[i] = 0;
5519
- pixels[i + 1] = 0;
5520
- pixels[i + 2] = 0;
5521
- pixels[i + 3] = 0;
5522
- }
5523
- }
5524
- return sharp5(pixels, {
5525
- raw: {
5526
- width: info.width,
5527
- height: info.height,
5528
- channels: 4
5529
- }
5530
- }).png().toBuffer();
5531
- }
5532
-
5533
5400
  // src/tools/app-icon/generate-app-icons.ts
5534
5401
  var TOOL_NAME6 = "generate-app-icons";
5535
5402
  var generateAppIconsInputSchema = z10.object({
@@ -5565,12 +5432,6 @@ var generateAppIconsInputSchema = z10.object({
5565
5432
  ]).optional().describe(
5566
5433
  "Logo alignment within the canvas (default: center or config default). Affects how the logo is positioned relative to the safe zone."
5567
5434
  ),
5568
- useAiMasking: z10.boolean().optional().default(false).describe(
5569
- "Use Gemini API for intelligent white masking on notification icon (default: false). When false, uses Sharp-based threshold conversion (faster, free, no API key needed). When true, uses Gemini AI for more sophisticated logo extraction (requires GEMINI_API_KEY)."
5570
- ),
5571
- logoPosition: z10.string().optional().describe(
5572
- "Additional prompt for logo positioning when using AI masking (e.g., 'centered', 'slightly above center'). Only used when useAiMasking is true."
5573
- ),
5574
5435
  skipExisting: z10.boolean().optional().default(false).describe("Skip generation if output file already exists (default: false)"),
5575
5436
  dryRun: z10.boolean().optional().default(false).describe(
5576
5437
  "Preview mode - shows what would be generated without actually generating"
@@ -5598,21 +5459,11 @@ var generateAppIconsTool = {
5598
5459
  - **Automatic Padding Removal**: Extracts actual logo from icon.png (removes surrounding padding)
5599
5460
  - **Smart Safe Zone Positioning**: Logo automatically fits within platform-specific circles
5600
5461
  - **Flexible Alignment**: Position logo center/left/right/top/bottom relative to safe zone
5601
- - **White Masking**: Sharp-based (default, fast, free) or AI-powered (Gemini, more sophisticated)
5462
+ - **White Masking**: Threshold-based (default) or alpha-based (preserves exact shape)
5602
5463
  - **Custom Background**: Only applies to ios-light.png. Others (adaptive-icon, splash, notification) are transparent
5603
5464
  - **Style Variants**: Generate themed icons (christmas, halloween, etc.) with style-specific defaults
5604
5465
  - **Config Integration**: Uses config.json appIcon settings for default colors and alignment
5605
5466
 
5606
- **White Masking Options:**
5607
- - **Default (useAiMasking=false)**: Sharp threshold conversion - fast, free, no API key needed
5608
- - **AI-Powered (useAiMasking=true)**: Gemini API - more sophisticated, requires GEMINI_API_KEY
5609
-
5610
- **\u26A0\uFE0F Important: After Generation**
5611
- After generating icons, always check **android-notification-icon.png**:
5612
- - If white masking is not clean (unwanted artifacts, incomplete conversion, or poor contrast)
5613
- - Regenerate with \`useAiMasking: true\` for better AI-powered masking
5614
- - Example: \`{ "appName": "my-app", "useAiMasking": true, "iconTypes": ["android-notification-icon"] }\`
5615
-
5616
5467
  **Example:**
5617
5468
  \`\`\`
5618
5469
  INPUT: my-app/icons/icon.png (source logo with padding)
@@ -5620,7 +5471,7 @@ INPUT: my-app/icons/icon.png (source logo with padding)
5620
5471
  OUTPUT: my-app/icons/ios-light.png (logo centered in safe zone)
5621
5472
  my-app/icons/adaptive-icon.png (logo aligned as specified)
5622
5473
  my-app/icons/splash-icon-light.png
5623
- my-app/icons/android-notification-icon.png (white mask, Sharp or AI)
5474
+ my-app/icons/android-notification-icon.png (white mask)
5624
5475
 
5625
5476
  With styleFolder='christmas':
5626
5477
  INPUT: my-app/icons/christmas/icon.png
@@ -5638,11 +5489,11 @@ function validateApp4(appName) {
5638
5489
  );
5639
5490
  }
5640
5491
  const productsDir = getProductsDir();
5641
- const configPath = path17.join(productsDir, app.slug, "config.json");
5492
+ const configPath = path15.join(productsDir, app.slug, "config.json");
5642
5493
  let config;
5643
- if (fs17.existsSync(configPath)) {
5494
+ if (fs15.existsSync(configPath)) {
5644
5495
  try {
5645
- const configData = fs17.readFileSync(configPath, "utf-8");
5496
+ const configData = fs15.readFileSync(configPath, "utf-8");
5646
5497
  config = JSON.parse(configData);
5647
5498
  } catch (error) {
5648
5499
  console.warn(
@@ -5661,7 +5512,7 @@ function buildGenerationTasks(slug, iconTypes, skipExisting, styleFolder) {
5661
5512
  const tasks = [];
5662
5513
  const baseIconPath = getBaseIconPath(slug, styleFolder);
5663
5514
  const iconsDir = getIconsDir(slug, styleFolder);
5664
- if (!fs17.existsSync(baseIconPath)) {
5515
+ if (!fs15.existsSync(baseIconPath)) {
5665
5516
  throw new Error(
5666
5517
  `Base icon not found: ${baseIconPath}
5667
5518
 
@@ -5670,7 +5521,7 @@ Please place your base icon at this location first.`
5670
5521
  }
5671
5522
  for (const iconType of iconTypes) {
5672
5523
  const outputPath = getIconOutputPath(slug, iconType, styleFolder);
5673
- if (skipExisting && fs17.existsSync(outputPath)) {
5524
+ if (skipExisting && fs15.existsSync(outputPath)) {
5674
5525
  continue;
5675
5526
  }
5676
5527
  tasks.push({
@@ -5682,7 +5533,7 @@ Please place your base icon at this location first.`
5682
5533
  }
5683
5534
  return { tasks, baseIconPath };
5684
5535
  }
5685
- async function generateIcons(tasks, backgroundColor, logoAlignment, useAiMasking, logoPosition, onProgress) {
5536
+ async function generateIcons(tasks, backgroundColor, logoAlignment, onProgress) {
5686
5537
  let generatedCount = 0;
5687
5538
  const errors = [];
5688
5539
  const total = tasks.length;
@@ -5696,28 +5547,16 @@ async function generateIcons(tasks, backgroundColor, logoAlignment, useAiMasking
5696
5547
  };
5697
5548
  onProgress?.(progress);
5698
5549
  try {
5699
- const outputDir = path17.dirname(task.outputPath);
5700
- if (!fs17.existsSync(outputDir)) {
5701
- fs17.mkdirSync(outputDir, { recursive: true });
5550
+ const outputDir = path15.dirname(task.outputPath);
5551
+ if (!fs15.existsSync(outputDir)) {
5552
+ fs15.mkdirSync(outputDir, { recursive: true });
5702
5553
  }
5703
5554
  if (task.iconType === "android-notification-icon") {
5704
- if (useAiMasking) {
5705
- const result = await applyWhiteMasking(
5706
- task.inputPath,
5707
- task.outputPath,
5708
- task.spec.size,
5709
- logoPosition
5710
- );
5711
- if (!result.success) {
5712
- throw new Error(result.error || "AI white masking failed");
5713
- }
5714
- } else {
5715
- const whiteMask = await convertToWhiteMask(task.inputPath);
5716
- await sharp6(whiteMask).resize(task.spec.size, task.spec.size, {
5717
- fit: "contain",
5718
- background: { r: 0, g: 0, b: 0, alpha: 0 }
5719
- }).png().toFile(task.outputPath);
5720
- }
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);
5721
5560
  } else {
5722
5561
  const iconBgColor = task.iconType === "ios-light" ? backgroundColor : "transparent";
5723
5562
  await resizeIconWithSafeZone(
@@ -5751,8 +5590,6 @@ async function handleGenerateAppIcons(input) {
5751
5590
  styleFolder,
5752
5591
  backgroundColor: bgColorInput,
5753
5592
  logoAlignment: logoAlignmentInput,
5754
- useAiMasking = false,
5755
- logoPosition,
5756
5593
  skipExisting = false,
5757
5594
  dryRun = false
5758
5595
  } = input;
@@ -5800,14 +5637,6 @@ async function handleGenerateAppIcons(input) {
5800
5637
  const iconTypes = requestedIconTypes || ALL_ICON_TYPES;
5801
5638
  results.push(`\u{1F3AF} Icon types: ${iconTypes.join(", ")}`);
5802
5639
  results.push(`\u{1F4D0} Logo alignment: ${logoAlignment}`);
5803
- if (useAiMasking) {
5804
- results.push(`\u{1F916} AI masking: enabled (uses Gemini API)`);
5805
- if (logoPosition) {
5806
- results.push(`\u{1F4CD} Logo positioning: ${logoPosition}`);
5807
- }
5808
- } else {
5809
- results.push(`\u26A1 AI masking: disabled (uses Sharp threshold)`);
5810
- }
5811
5640
  let tasks;
5812
5641
  let baseIconPath;
5813
5642
  try {
@@ -5875,8 +5704,6 @@ async function handleGenerateAppIcons(input) {
5875
5704
  tasks,
5876
5705
  bgColor,
5877
5706
  logoAlignment,
5878
- useAiMasking,
5879
- logoPosition,
5880
5707
  (progress) => {
5881
5708
  const progressPrefix = `[${progress.current}/${progress.total}]`;
5882
5709
  if (progress.status === "generating") {
@@ -5908,21 +5735,6 @@ async function handleGenerateAppIcons(input) {
5908
5735
  \u{1F4C1} Output location: ${iconsDir}/`);
5909
5736
  results.push(`
5910
5737
  \u2705 Icon generation complete!`);
5911
- const hasNotificationIcon = tasks.some((t) => t.iconType === "android-notification-icon") && !generationResult.errors.some(
5912
- (e) => e.iconType === "android-notification-icon"
5913
- );
5914
- if (hasNotificationIcon && !useAiMasking) {
5915
- results.push(
5916
- `
5917
- \u26A0\uFE0F IMPORTANT: Check android-notification-icon.png`
5918
- );
5919
- results.push(
5920
- ` If white masking looks incorrect (artifacts, incomplete conversion, poor contrast):`
5921
- );
5922
- results.push(
5923
- ` Regenerate with AI masking: { "appName": "${appInfo.slug}", "useAiMasking": true, "iconTypes": ["android-notification-icon"]${styleFolder ? `, "styleFolder": "${styleFolder}"` : ""} }`
5924
- );
5925
- }
5926
5738
  return {
5927
5739
  content: [
5928
5740
  {
@@ -5936,9 +5748,32 @@ async function handleGenerateAppIcons(input) {
5936
5748
  // src/tools/app-icon/stylize-app-icon.ts
5937
5749
  import { z as z11 } from "zod";
5938
5750
  import { zodToJsonSchema as zodToJsonSchema11 } from "zod-to-json-schema";
5939
- import fs18 from "fs";
5940
- import path18 from "path";
5941
- import sharp7 from "sharp";
5751
+ import fs17 from "fs";
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";
5758
+ import { GoogleGenAI as GoogleGenAI3 } from "@google/genai";
5759
+ function getGeminiClient3() {
5760
+ const apiKey = getGeminiApiKey();
5761
+ return new GoogleGenAI3({ apiKey });
5762
+ }
5763
+ function readImageAsBase643(imagePath) {
5764
+ const buffer = fs16.readFileSync(imagePath);
5765
+ const base64 = buffer.toString("base64");
5766
+ const ext = path16.extname(imagePath).toLowerCase();
5767
+ let mimeType = "image/png";
5768
+ if (ext === ".jpg" || ext === ".jpeg") {
5769
+ mimeType = "image/jpeg";
5770
+ } else if (ext === ".webp") {
5771
+ mimeType = "image/webp";
5772
+ }
5773
+ return { data: base64, mimeType };
5774
+ }
5775
+
5776
+ // src/tools/app-icon/stylize-app-icon.ts
5942
5777
  var TOOL_NAME7 = "stylize-app-icon";
5943
5778
  var stylizeAppIconInputSchema = z11.object({
5944
5779
  appName: z11.string().describe(
@@ -6072,12 +5907,12 @@ Generate the stylized icon with transparent background now.`;
6072
5907
  for (const part of parts) {
6073
5908
  if (part.inlineData?.data) {
6074
5909
  const imageBuffer = Buffer.from(part.inlineData.data, "base64");
6075
- const outputDir = path18.dirname(outputPath);
6076
- if (!fs18.existsSync(outputDir)) {
6077
- fs18.mkdirSync(outputDir, { recursive: true });
5910
+ const outputDir = path17.dirname(outputPath);
5911
+ if (!fs17.existsSync(outputDir)) {
5912
+ fs17.mkdirSync(outputDir, { recursive: true });
6078
5913
  }
6079
- const processedImage = await sharp7(imageBuffer).ensureAlpha().png().toBuffer();
6080
- await sharp7(processedImage).toFile(outputPath);
5914
+ const processedImage = await sharp6(imageBuffer).ensureAlpha().png().toBuffer();
5915
+ await sharp6(processedImage).toFile(outputPath);
6081
5916
  return { success: true };
6082
5917
  }
6083
5918
  }
@@ -6117,7 +5952,7 @@ async function handleStylizeAppIcon(input) {
6117
5952
  };
6118
5953
  }
6119
5954
  const baseIconPath = getBaseIconPath(appInfo.slug);
6120
- if (!fs18.existsSync(baseIconPath)) {
5955
+ if (!fs17.existsSync(baseIconPath)) {
6121
5956
  return {
6122
5957
  content: [
6123
5958
  {
@@ -6211,13 +6046,13 @@ Next step: Run generate-app-icons with styleFolder='${styleFolder}' to create pl
6211
6046
  }
6212
6047
 
6213
6048
  // src/tools/apps/init.ts
6214
- import fs19 from "fs";
6215
- import path19 from "path";
6049
+ import fs18 from "fs";
6050
+ import path18 from "path";
6216
6051
  import { z as z12 } from "zod";
6217
6052
  import { zodToJsonSchema as zodToJsonSchema12 } from "zod-to-json-schema";
6218
6053
  var listSlugDirs = (dir) => {
6219
- if (!fs19.existsSync(dir)) return [];
6220
- return fs19.readdirSync(dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
6054
+ if (!fs18.existsSync(dir)) return [];
6055
+ return fs18.readdirSync(dir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
6221
6056
  };
6222
6057
  var initProjectInputSchema = z12.object({
6223
6058
  slug: z12.string().trim().optional().describe(
@@ -6242,7 +6077,7 @@ Steps:
6242
6077
  inputSchema: inputSchema12
6243
6078
  };
6244
6079
  async function handleInitProject(input) {
6245
- const pullDataDir = path19.join(getPullDataDir(), "products");
6080
+ const pullDataDir = path18.join(getPullDataDir(), "products");
6246
6081
  const publicDir = getProductsDir();
6247
6082
  const pullDataSlugs = listSlugDirs(pullDataDir);
6248
6083
  const publicSlugs = listSlugDirs(publicDir);
@@ -6325,14 +6160,14 @@ async function handleInitProject(input) {
6325
6160
  }
6326
6161
 
6327
6162
  // src/tools/content/create-blog-html.ts
6328
- import fs21 from "fs";
6329
- import path21 from "path";
6163
+ import fs20 from "fs";
6164
+ import path20 from "path";
6330
6165
  import { z as z13 } from "zod";
6331
6166
  import { zodToJsonSchema as zodToJsonSchema13 } from "zod-to-json-schema";
6332
6167
 
6333
6168
  // src/utils/blog.util.ts
6334
- import fs20 from "fs";
6335
- import path20 from "path";
6169
+ import fs19 from "fs";
6170
+ import path19 from "path";
6336
6171
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
6337
6172
  var BLOG_ROOT = "blogs";
6338
6173
  var removeDiacritics = (value) => value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
@@ -6420,13 +6255,13 @@ function resolveTargetLocales(input) {
6420
6255
  return fallback ? [fallback] : [];
6421
6256
  }
6422
6257
  function getBlogOutputPaths(options) {
6423
- const baseDir = path20.join(
6258
+ const baseDir = path19.join(
6424
6259
  options.publicDir,
6425
6260
  BLOG_ROOT,
6426
6261
  options.appSlug,
6427
6262
  options.slug
6428
6263
  );
6429
- const filePath = path20.join(baseDir, `${options.locale}.html`);
6264
+ const filePath = path19.join(baseDir, `${options.locale}.html`);
6430
6265
  const publicBasePath = toPublicBlogBase(options.appSlug, options.slug);
6431
6266
  return { baseDir, filePath, publicBasePath };
6432
6267
  }
@@ -6451,18 +6286,18 @@ function findExistingBlogPosts({
6451
6286
  publicDir,
6452
6287
  limit = 2
6453
6288
  }) {
6454
- const blogAppDir = path20.join(publicDir, BLOG_ROOT, appSlug);
6455
- if (!fs20.existsSync(blogAppDir)) {
6289
+ const blogAppDir = path19.join(publicDir, BLOG_ROOT, appSlug);
6290
+ if (!fs19.existsSync(blogAppDir)) {
6456
6291
  return [];
6457
6292
  }
6458
6293
  const posts = [];
6459
- const subdirs = fs20.readdirSync(blogAppDir, { withFileTypes: true });
6294
+ const subdirs = fs19.readdirSync(blogAppDir, { withFileTypes: true });
6460
6295
  for (const subdir of subdirs) {
6461
6296
  if (!subdir.isDirectory()) continue;
6462
- const localeFile = path20.join(blogAppDir, subdir.name, `${locale}.html`);
6463
- if (!fs20.existsSync(localeFile)) continue;
6297
+ const localeFile = path19.join(blogAppDir, subdir.name, `${locale}.html`);
6298
+ if (!fs19.existsSync(localeFile)) continue;
6464
6299
  try {
6465
- const htmlContent = fs20.readFileSync(localeFile, "utf-8");
6300
+ const htmlContent = fs19.readFileSync(localeFile, "utf-8");
6466
6301
  const { meta, body } = parseBlogHtml(htmlContent);
6467
6302
  if (meta && meta.locale === locale) {
6468
6303
  posts.push({
@@ -6605,7 +6440,7 @@ async function handleCreateBlogHtml(input) {
6605
6440
  }
6606
6441
  const output = {
6607
6442
  slug,
6608
- baseDir: path21.join(publicDir, "blogs", appSlug, slug),
6443
+ baseDir: path20.join(publicDir, "blogs", appSlug, slug),
6609
6444
  files: [],
6610
6445
  coverImage: coverImage && coverImage.trim().length > 0 ? coverImage.trim() : `/products/${appSlug}/og-image.png`,
6611
6446
  metaByLocale: {}
@@ -6619,7 +6454,7 @@ async function handleCreateBlogHtml(input) {
6619
6454
  })
6620
6455
  );
6621
6456
  const existing = plannedFiles.filter(
6622
- ({ filePath }) => fs21.existsSync(filePath)
6457
+ ({ filePath }) => fs20.existsSync(filePath)
6623
6458
  );
6624
6459
  if (existing.length > 0 && !overwrite) {
6625
6460
  const existingList = existing.map((f) => f.filePath).join("\n- ");
@@ -6628,7 +6463,7 @@ async function handleCreateBlogHtml(input) {
6628
6463
  - ${existingList}`
6629
6464
  );
6630
6465
  }
6631
- fs21.mkdirSync(output.baseDir, { recursive: true });
6466
+ fs20.mkdirSync(output.baseDir, { recursive: true });
6632
6467
  for (const locale of targetLocales) {
6633
6468
  const { filePath } = getBlogOutputPaths({
6634
6469
  appSlug,
@@ -6654,7 +6489,7 @@ async function handleCreateBlogHtml(input) {
6654
6489
  meta,
6655
6490
  content
6656
6491
  });
6657
- fs21.writeFileSync(filePath, html, "utf-8");
6492
+ fs20.writeFileSync(filePath, html, "utf-8");
6658
6493
  output.files.push({ locale, path: filePath });
6659
6494
  }
6660
6495
  const summaryLines = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-resource-mcp",
3
- "version": "1.8.9",
3
+ "version": "1.8.11",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",