pabal-resource-mcp 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3659,13 +3659,58 @@ async function getImageDimensions2(imagePath) {
3659
3659
  height: metadata.height
3660
3660
  };
3661
3661
  }
3662
+ async function detectEdgeColor(imagePath) {
3663
+ const image = sharp2(imagePath);
3664
+ const metadata = await image.metadata();
3665
+ const width = metadata.width || 100;
3666
+ const height = metadata.height || 100;
3667
+ const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
3668
+ const channels = info.channels;
3669
+ const colorCounts = /* @__PURE__ */ new Map();
3670
+ const sampleEdgePixel = (x, y) => {
3671
+ const idx = (y * width + x) * channels;
3672
+ const r = data[idx];
3673
+ const g = data[idx + 1];
3674
+ const b = data[idx + 2];
3675
+ const qr = Math.round(r / 16) * 16;
3676
+ const qg = Math.round(g / 16) * 16;
3677
+ const qb = Math.round(b / 16) * 16;
3678
+ const key = `${qr},${qg},${qb}`;
3679
+ const existing = colorCounts.get(key);
3680
+ if (existing) {
3681
+ existing.count++;
3682
+ } else {
3683
+ colorCounts.set(key, { count: 1, color: { r: qr, g: qg, b: qb } });
3684
+ }
3685
+ };
3686
+ for (let x = 0; x < width; x += 2) {
3687
+ sampleEdgePixel(x, 0);
3688
+ sampleEdgePixel(x, height - 1);
3689
+ }
3690
+ for (let y = 0; y < height; y += 2) {
3691
+ sampleEdgePixel(0, y);
3692
+ sampleEdgePixel(width - 1, y);
3693
+ }
3694
+ let maxCount = 0;
3695
+ let dominantColor = { r: 255, g: 255, b: 255 };
3696
+ for (const { count, color } of colorCounts.values()) {
3697
+ if (count > maxCount) {
3698
+ maxCount = count;
3699
+ dominantColor = color;
3700
+ }
3701
+ }
3702
+ return dominantColor;
3703
+ }
3662
3704
  async function resizeImage(inputPath, outputPath, targetDimensions) {
3705
+ const bgColor = await detectEdgeColor(inputPath);
3663
3706
  await sharp2(inputPath).resize(targetDimensions.width, targetDimensions.height, {
3664
- fit: "fill",
3665
- // Exact resize to target dimensions
3666
- withoutEnlargement: false
3707
+ fit: "contain",
3708
+ // Preserve aspect ratio
3709
+ withoutEnlargement: false,
3667
3710
  // Allow enlargement if needed
3668
- }).toFile(outputPath + ".tmp");
3711
+ background: bgColor
3712
+ // Use detected edge color
3713
+ }).flatten({ background: bgColor }).png().toFile(outputPath + ".tmp");
3669
3714
  fs11.renameSync(outputPath + ".tmp", outputPath);
3670
3715
  }
3671
3716
  async function validateAndResizeImage(sourcePath, translatedPath) {
@@ -3717,7 +3762,10 @@ var localizeScreenshotsInputSchema = z7.object({
3717
3762
  ),
3718
3763
  deviceTypes: z7.array(z7.enum(["phone", "tablet"])).optional().default(["phone", "tablet"]).describe("Device types to process (default: both phone and tablet)"),
3719
3764
  dryRun: z7.boolean().optional().default(false).describe("Preview mode - shows what would be translated without actually translating"),
3720
- skipExisting: z7.boolean().optional().default(true).describe("Skip translation if target file already exists (default: true)")
3765
+ skipExisting: z7.boolean().optional().default(true).describe("Skip translation if target file already exists (default: true)"),
3766
+ screenshotNumbers: z7.array(z7.number().int().positive()).optional().describe(
3767
+ "Specific screenshot numbers to process (e.g., [1, 3, 5]). If not provided, all screenshots will be processed."
3768
+ )
3721
3769
  });
3722
3770
  var jsonSchema7 = zodToJsonSchema7(localizeScreenshotsInputSchema, {
3723
3771
  name: "LocalizeScreenshotsInput",
@@ -3832,7 +3880,8 @@ async function handleLocalizeScreenshots(input) {
3832
3880
  targetLocales: requestedTargetLocales,
3833
3881
  deviceTypes = ["phone", "tablet"],
3834
3882
  dryRun = false,
3835
- skipExisting = true
3883
+ skipExisting = true,
3884
+ screenshotNumbers
3836
3885
  } = input;
3837
3886
  const results = [];
3838
3887
  let appInfo;
@@ -3884,9 +3933,20 @@ async function handleLocalizeScreenshots(input) {
3884
3933
  }
3885
3934
  results.push(`\u{1F3AF} Target locales: ${targetLocales.join(", ")}`);
3886
3935
  const sourceScreenshots = scanLocaleScreenshots(appInfo.slug, primaryLocale);
3887
- const filteredScreenshots = sourceScreenshots.filter(
3936
+ let filteredScreenshots = sourceScreenshots.filter(
3888
3937
  (s) => deviceTypes.includes(s.type)
3889
3938
  );
3939
+ if (screenshotNumbers && screenshotNumbers.length > 0) {
3940
+ filteredScreenshots = filteredScreenshots.filter((s) => {
3941
+ const match = s.filename.match(/^(\d+)\./);
3942
+ if (match) {
3943
+ const num = parseInt(match[1], 10);
3944
+ return screenshotNumbers.includes(num);
3945
+ }
3946
+ return false;
3947
+ });
3948
+ results.push(`\u{1F522} Filtering screenshots: ${screenshotNumbers.join(", ")}`);
3949
+ }
3890
3950
  if (filteredScreenshots.length === 0) {
3891
3951
  const screenshotsDir2 = getScreenshotsDir(appInfo.slug);
3892
3952
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pabal-resource-mcp",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "type": "module",
5
5
  "description": "MCP server for ASO data management with shared types and utilities",
6
6
  "author": "skyu",