lingo.dev 0.79.0 → 0.79.2

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/build/cli.mjs CHANGED
@@ -854,10 +854,14 @@ function getBuckets(i18nConfig) {
854
854
  const result = Object.entries(i18nConfig.buckets).map(([bucketType, bucketEntry]) => {
855
855
  const includeItems = bucketEntry.include.map((item) => resolveBucketItem(item));
856
856
  const excludeItems = bucketEntry.exclude?.map((item) => resolveBucketItem(item));
857
- return {
857
+ const config = {
858
858
  type: bucketType,
859
- config: extractPathPatterns(i18nConfig.locale.source, includeItems, excludeItems)
859
+ paths: extractPathPatterns(i18nConfig.locale.source, includeItems, excludeItems)
860
860
  };
861
+ if (bucketEntry.injectLocale) {
862
+ config.injectLocale = bucketEntry.injectLocale;
863
+ }
864
+ return config;
861
865
  });
862
866
  return result;
863
867
  }
@@ -947,7 +951,7 @@ var files_default = new Command4().command("files").description("Print out the l
947
951
  }
948
952
  const buckets = getBuckets(i18nConfig);
949
953
  for (const bucket of buckets) {
950
- for (const bucketConfig of bucket.config) {
954
+ for (const bucketConfig of bucket.paths) {
951
955
  const sourceLocale = resolveOverriddenLocale2(i18nConfig.locale.source, bucketConfig.delimiter);
952
956
  const sourcePath = bucketConfig.pathPattern.replace(/\[locale\]/g, sourceLocale);
953
957
  const targetPaths = i18nConfig.locale.targets.map((_targetLocale) => {
@@ -987,7 +991,7 @@ import { bucketTypeSchema, localeCodeSchema, resolveOverriddenLocale as resolveO
987
991
  import { LingoDotDevEngine } from "@lingo.dev/_sdk";
988
992
  import { Command as Command6 } from "interactive-commander";
989
993
  import Z4 from "zod";
990
- import _19 from "lodash";
994
+ import _20 from "lodash";
991
995
  import Ora5 from "ora";
992
996
 
993
997
  // src/cli/loaders/_utils.ts
@@ -1194,7 +1198,7 @@ function createTextFileLoader(pathPattern) {
1194
1198
  const trimmedResult = result.trim();
1195
1199
  return trimmedResult;
1196
1200
  },
1197
- async push(locale, data, _21, originalLocale) {
1201
+ async push(locale, data, _22, originalLocale) {
1198
1202
  const draftPath = pathPattern.replaceAll("[locale]", locale);
1199
1203
  const finalPath = path10.resolve(draftPath);
1200
1204
  const dirPath = path10.dirname(finalPath);
@@ -1636,7 +1640,7 @@ function createPropertiesLoader() {
1636
1640
  return result;
1637
1641
  },
1638
1642
  async push(locale, payload) {
1639
- const result = Object.entries(payload).filter(([_21, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1643
+ const result = Object.entries(payload).filter(([_22, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1640
1644
  return result;
1641
1645
  }
1642
1646
  });
@@ -1903,10 +1907,10 @@ function createUnlocalizableLoader(isCacheRestore = false, returnUnlocalizedKeys
1903
1907
  }
1904
1908
  }
1905
1909
  return false;
1906
- }).map(([key, _21]) => key);
1907
- const result = _10.omitBy(input2, (_21, key) => passthroughKeys.includes(key));
1910
+ }).map(([key, _22]) => key);
1911
+ const result = _10.omitBy(input2, (_22, key) => passthroughKeys.includes(key));
1908
1912
  if (returnUnlocalizedKeys) {
1909
- result.unlocalizable = _10.omitBy(input2, (_21, key) => !passthroughKeys.includes(key));
1913
+ result.unlocalizable = _10.omitBy(input2, (_22, key) => !passthroughKeys.includes(key));
1910
1914
  }
1911
1915
  return result;
1912
1916
  },
@@ -2989,6 +2993,34 @@ function parseVueFile(input2) {
2989
2993
  return { before, after, i18n };
2990
2994
  }
2991
2995
 
2996
+ // src/cli/loaders/inject-locale.ts
2997
+ import _18 from "lodash";
2998
+ function createInjectLocaleLoader(injectLocaleKeys) {
2999
+ return createLoader({
3000
+ async pull(locale, data) {
3001
+ if (!injectLocaleKeys) {
3002
+ return data;
3003
+ }
3004
+ const omitKeys = injectLocaleKeys.filter((key) => {
3005
+ return _18.get(data, key) === locale;
3006
+ });
3007
+ const result = _18.omit(data, omitKeys);
3008
+ return result;
3009
+ },
3010
+ async push(locale, data, originalInput, originalLocale) {
3011
+ if (!injectLocaleKeys) {
3012
+ return data;
3013
+ }
3014
+ injectLocaleKeys.forEach((key) => {
3015
+ if (_18.get(originalInput, key) === originalLocale) {
3016
+ _18.set(data, key, locale);
3017
+ }
3018
+ });
3019
+ return data;
3020
+ }
3021
+ });
3022
+ }
3023
+
2992
3024
  // src/cli/loaders/index.ts
2993
3025
  function createBucketLoader(bucketType, bucketPathPattern, options) {
2994
3026
  switch (bucketType) {
@@ -3023,6 +3055,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options) {
3023
3055
  createTextFileLoader(bucketPathPattern),
3024
3056
  createPrettierLoader({ parser: "json", bucketPathPattern }),
3025
3057
  createJsonLoader(),
3058
+ createInjectLocaleLoader(options.injectLocale),
3026
3059
  createFlatLoader(),
3027
3060
  createSyncLoader(),
3028
3061
  createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
@@ -3168,7 +3201,7 @@ import path12 from "path";
3168
3201
  import Z3 from "zod";
3169
3202
  import YAML3 from "yaml";
3170
3203
  import { MD5 } from "object-hash";
3171
- import _18 from "lodash";
3204
+ import _19 from "lodash";
3172
3205
  function createLockfileHelper() {
3173
3206
  return {
3174
3207
  isLockfileExists: () => {
@@ -3178,23 +3211,23 @@ function createLockfileHelper() {
3178
3211
  registerSourceData: (pathPattern, sourceData) => {
3179
3212
  const lockfile = _loadLockfile();
3180
3213
  const sectionKey = MD5(pathPattern);
3181
- const sectionChecksums = _18.mapValues(sourceData, (value) => MD5(value));
3214
+ const sectionChecksums = _19.mapValues(sourceData, (value) => MD5(value));
3182
3215
  lockfile.checksums[sectionKey] = sectionChecksums;
3183
3216
  _saveLockfile(lockfile);
3184
3217
  },
3185
3218
  registerPartialSourceData: (pathPattern, partialSourceData) => {
3186
3219
  const lockfile = _loadLockfile();
3187
3220
  const sectionKey = MD5(pathPattern);
3188
- const sectionChecksums = _18.mapValues(partialSourceData, (value) => MD5(value));
3189
- lockfile.checksums[sectionKey] = _18.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
3221
+ const sectionChecksums = _19.mapValues(partialSourceData, (value) => MD5(value));
3222
+ lockfile.checksums[sectionKey] = _19.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
3190
3223
  _saveLockfile(lockfile);
3191
3224
  },
3192
3225
  extractUpdatedData: (pathPattern, sourceData) => {
3193
3226
  const lockfile = _loadLockfile();
3194
3227
  const sectionKey = MD5(pathPattern);
3195
- const currentChecksums = _18.mapValues(sourceData, (value) => MD5(value));
3228
+ const currentChecksums = _19.mapValues(sourceData, (value) => MD5(value));
3196
3229
  const savedChecksums = lockfile.checksums[sectionKey] || {};
3197
- const updatedData = _18.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
3230
+ const updatedData = _19.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
3198
3231
  return updatedData;
3199
3232
  }
3200
3233
  };
@@ -3305,7 +3338,16 @@ function _tryParseJSON(line) {
3305
3338
  }
3306
3339
 
3307
3340
  // src/cli/cmd/i18n.ts
3308
- var i18n_default = new Command6().command("i18n").description("Run Localization engine").helpOption("-h, --help", "Show help").option("--locale <locale>", "Locale to process", (val, prev) => prev ? [...prev, val] : [val]).option("--bucket <bucket>", "Bucket to process", (val, prev) => prev ? [...prev, val] : [val]).option("--key <key>", "Key to process. Process only a specific translation key, useful for debugging or updating a single entry").option("--frozen", `Run in read-only mode - fails if any translations need updating, useful for CI/CD pipelines to detect missing translations`).option("--force", "Ignore lockfile and process all keys, useful for full re-translation").option("--verbose", "Show detailed output including intermediate processing data and API communication details").option("--interactive", "Enable interactive mode for reviewing and editing translations before they are applied").option("--api-key <api-key>", "Explicitly set the API key to use, override the default API key from settings").option("--debug", "Pause execution at start for debugging purposes, waits for user confirmation before proceeding").option("--strict", "Stop processing on first error instead of continuing with other locales/buckets").action(async function(options) {
3341
+ var i18n_default = new Command6().command("i18n").description("Run Localization engine").helpOption("-h, --help", "Show help").option("--locale <locale>", "Locale to process", (val, prev) => prev ? [...prev, val] : [val]).option("--bucket <bucket>", "Bucket to process", (val, prev) => prev ? [...prev, val] : [val]).option(
3342
+ "--key <key>",
3343
+ "Key to process. Process only a specific translation key, useful for debugging or updating a single entry"
3344
+ ).option(
3345
+ "--file [files...]",
3346
+ "File to process. Process only a specific path, may contain asterisk * to match multiple files. Useful if you have a lot of files and want to focus on a specific one. Specify more files separated by commas or spaces."
3347
+ ).option(
3348
+ "--frozen",
3349
+ `Run in read-only mode - fails if any translations need updating, useful for CI/CD pipelines to detect missing translations`
3350
+ ).option("--force", "Ignore lockfile and process all keys, useful for full re-translation").option("--verbose", "Show detailed output including intermediate processing data and API communication details").option("--interactive", "Enable interactive mode for reviewing and editing translations before they are applied").option("--api-key <api-key>", "Explicitly set the API key to use, override the default API key from settings").option("--debug", "Pause execution at start for debugging purposes, waits for user confirmation before proceeding").option("--strict", "Stop processing on first error instead of continuing with other locales/buckets").action(async function(options) {
3309
3351
  updateGitignore();
3310
3352
  const ora = Ora5();
3311
3353
  const flags = parseFlags(options);
@@ -3335,22 +3377,41 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3335
3377
  buckets = buckets.filter((bucket) => flags.bucket.includes(bucket.type));
3336
3378
  }
3337
3379
  ora.succeed("Buckets retrieved");
3380
+ if (flags.file?.length) {
3381
+ buckets = buckets.map((bucket) => {
3382
+ const paths = bucket.paths.filter((path15) => flags.file.find((file) => path15.pathPattern?.match(file)));
3383
+ return { ...bucket, paths };
3384
+ }).filter((bucket) => bucket.paths.length > 0);
3385
+ if (buckets.length === 0) {
3386
+ ora.fail("No buckets found. All buckets were filtered out by --file option.");
3387
+ process.exit(1);
3388
+ } else {
3389
+ ora.info(`\x1B[36mProcessing only filtered buckets:\x1B[0m`);
3390
+ buckets.map((bucket) => {
3391
+ ora.info(` ${bucket.type}:`);
3392
+ bucket.paths.forEach((path15) => {
3393
+ ora.info(` - ${path15.pathPattern}`);
3394
+ });
3395
+ });
3396
+ }
3397
+ }
3338
3398
  const targetLocales = flags.locale?.length ? flags.locale : i18nConfig.locale.targets;
3339
3399
  const lockfileHelper = createLockfileHelper();
3340
3400
  ora.start("Ensuring i18n.lock exists...");
3341
3401
  if (!lockfileHelper.isLockfileExists()) {
3342
3402
  ora.start("Creating i18n.lock...");
3343
3403
  for (const bucket of buckets) {
3344
- for (const bucketConfig of bucket.config) {
3345
- const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketConfig.delimiter);
3346
- const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
3404
+ for (const bucketPath of bucket.paths) {
3405
+ const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3406
+ const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3347
3407
  isCacheRestore: false,
3348
- defaultLocale: sourceLocale
3408
+ defaultLocale: sourceLocale,
3409
+ injectLocale: bucket.injectLocale
3349
3410
  });
3350
3411
  bucketLoader.setDefaultLocale(sourceLocale);
3351
3412
  await bucketLoader.init();
3352
3413
  const sourceData = await bucketLoader.pull(i18nConfig.locale.source);
3353
- lockfileHelper.registerSourceData(bucketConfig.pathPattern, sourceData);
3414
+ lockfileHelper.registerSourceData(bucketPath.pathPattern, sourceData);
3354
3415
  }
3355
3416
  }
3356
3417
  ora.succeed("i18n.lock created");
@@ -3364,13 +3425,14 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3364
3425
  const cacheOra = Ora5({ indent: 2 });
3365
3426
  for (const bucket of buckets) {
3366
3427
  cacheOra.info(`Processing bucket: ${bucket.type}`);
3367
- for (const bucketConfig of bucket.config) {
3428
+ for (const bucketPath of bucket.paths) {
3368
3429
  const bucketOra = Ora5({ indent: 4 });
3369
- bucketOra.info(`Processing path: ${bucketConfig.pathPattern}`);
3370
- const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketConfig.delimiter);
3371
- const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
3430
+ bucketOra.info(`Processing path: ${bucketPath.pathPattern}`);
3431
+ const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3432
+ const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3372
3433
  isCacheRestore: true,
3373
- defaultLocale: sourceLocale
3434
+ defaultLocale: sourceLocale,
3435
+ injectLocale: bucket.injectLocale
3374
3436
  });
3375
3437
  bucketLoader.setDefaultLocale(sourceLocale);
3376
3438
  await bucketLoader.init();
@@ -3386,7 +3448,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3386
3448
  }
3387
3449
  }
3388
3450
  await bucketLoader.push(targetLocale, targetData);
3389
- lockfileHelper.registerPartialSourceData(bucketConfig.pathPattern, cachedSourceData);
3451
+ lockfileHelper.registerPartialSourceData(bucketPath.pathPattern, cachedSourceData);
3390
3452
  bucketOra.succeed(
3391
3453
  `[${sourceLocale} -> ${targetLocale}] Recovered ${Object.keys(cachedSourceData).length} entries from cache`
3392
3454
  );
@@ -3404,29 +3466,30 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3404
3466
  ora.start("Checking for lockfile updates...");
3405
3467
  let requiresUpdate = null;
3406
3468
  bucketLoop: for (const bucket of buckets) {
3407
- for (const bucketConfig of bucket.config) {
3408
- const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketConfig.delimiter);
3409
- const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
3469
+ for (const bucketPath of bucket.paths) {
3470
+ const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3471
+ const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3410
3472
  isCacheRestore: false,
3411
3473
  defaultLocale: sourceLocale,
3412
- returnUnlocalizedKeys: true
3474
+ returnUnlocalizedKeys: true,
3475
+ injectLocale: bucket.injectLocale
3413
3476
  });
3414
3477
  bucketLoader.setDefaultLocale(sourceLocale);
3415
3478
  await bucketLoader.init();
3416
3479
  const { unlocalizable: sourceUnlocalizable, ...sourceData } = await bucketLoader.pull(
3417
3480
  i18nConfig.locale.source
3418
3481
  );
3419
- const updatedSourceData = lockfileHelper.extractUpdatedData(bucketConfig.pathPattern, sourceData);
3482
+ const updatedSourceData = lockfileHelper.extractUpdatedData(bucketPath.pathPattern, sourceData);
3420
3483
  if (Object.keys(updatedSourceData).length > 0) {
3421
3484
  requiresUpdate = "updated";
3422
3485
  break bucketLoop;
3423
3486
  }
3424
3487
  for (const _targetLocale of targetLocales) {
3425
- const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketConfig.delimiter);
3488
+ const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketPath.delimiter);
3426
3489
  const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
3427
- const missingKeys = _19.difference(Object.keys(sourceData), Object.keys(targetData));
3428
- const extraKeys = _19.difference(Object.keys(targetData), Object.keys(sourceData));
3429
- const unlocalizableDataDiff = !_19.isEqual(sourceUnlocalizable, targetUnlocalizable);
3490
+ const missingKeys = _20.difference(Object.keys(sourceData), Object.keys(targetData));
3491
+ const extraKeys = _20.difference(Object.keys(targetData), Object.keys(sourceData));
3492
+ const unlocalizableDataDiff = !_20.isEqual(sourceUnlocalizable, targetUnlocalizable);
3430
3493
  if (missingKeys.length > 0) {
3431
3494
  requiresUpdate = "missing";
3432
3495
  break bucketLoop;
@@ -3460,22 +3523,23 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3460
3523
  try {
3461
3524
  console.log();
3462
3525
  ora.info(`Processing bucket: ${bucket.type}`);
3463
- for (const bucketConfig of bucket.config) {
3464
- const bucketOra = Ora5({ indent: 2 }).info(`Processing path: ${bucketConfig.pathPattern}`);
3465
- const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketConfig.delimiter);
3466
- const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
3526
+ for (const bucketPath of bucket.paths) {
3527
+ const bucketOra = Ora5({ indent: 2 }).info(`Processing path: ${bucketPath.pathPattern}`);
3528
+ const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3529
+ const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3467
3530
  isCacheRestore: false,
3468
- defaultLocale: sourceLocale
3531
+ defaultLocale: sourceLocale,
3532
+ injectLocale: bucket.injectLocale
3469
3533
  });
3470
3534
  bucketLoader.setDefaultLocale(sourceLocale);
3471
3535
  await bucketLoader.init();
3472
3536
  let sourceData = await bucketLoader.pull(sourceLocale);
3473
3537
  for (const _targetLocale of targetLocales) {
3474
- const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketConfig.delimiter);
3538
+ const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketPath.delimiter);
3475
3539
  try {
3476
3540
  bucketOra.start(`[${sourceLocale} -> ${targetLocale}] (0%) Localization in progress...`);
3477
3541
  sourceData = await bucketLoader.pull(sourceLocale);
3478
- const updatedSourceData = flags.force ? sourceData : lockfileHelper.extractUpdatedData(bucketConfig.pathPattern, sourceData);
3542
+ const updatedSourceData = flags.force ? sourceData : lockfileHelper.extractUpdatedData(bucketPath.pathPattern, sourceData);
3479
3543
  const targetData = await bucketLoader.pull(targetLocale);
3480
3544
  let processableData = calculateDataDelta({
3481
3545
  sourceData,
@@ -3483,7 +3547,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3483
3547
  targetData
3484
3548
  });
3485
3549
  if (flags.key) {
3486
- processableData = _19.pickBy(processableData, (_21, key) => key === flags.key);
3550
+ processableData = _20.pickBy(processableData, (_22, key) => key === flags.key);
3487
3551
  }
3488
3552
  if (flags.verbose) {
3489
3553
  bucketOra.info(JSON.stringify(processableData, null, 2));
@@ -3519,11 +3583,11 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3519
3583
  if (flags.verbose) {
3520
3584
  bucketOra.info(JSON.stringify(processedTargetData, null, 2));
3521
3585
  }
3522
- let finalTargetData = _19.merge({}, sourceData, targetData, processedTargetData);
3586
+ let finalTargetData = _20.merge({}, sourceData, targetData, processedTargetData);
3523
3587
  if (flags.interactive) {
3524
3588
  bucketOra.stop();
3525
3589
  const reviewedData = await reviewChanges({
3526
- pathPattern: bucketConfig.pathPattern,
3590
+ pathPattern: bucketPath.pathPattern,
3527
3591
  targetLocale,
3528
3592
  currentData: targetData,
3529
3593
  proposedData: finalTargetData,
@@ -3531,9 +3595,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3531
3595
  force: flags.force
3532
3596
  });
3533
3597
  finalTargetData = reviewedData;
3534
- bucketOra.start(`Applying changes to ${bucketConfig} (${targetLocale})`);
3598
+ bucketOra.start(`Applying changes to ${bucketPath} (${targetLocale})`);
3535
3599
  }
3536
- const finalDiffSize = _19.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
3600
+ const finalDiffSize = _20.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
3537
3601
  await bucketLoader.push(targetLocale, finalTargetData);
3538
3602
  if (finalDiffSize > 0 || flags.force) {
3539
3603
  bucketOra.succeed(`[${sourceLocale} -> ${targetLocale}] Localization completed`);
@@ -3550,7 +3614,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3550
3614
  }
3551
3615
  }
3552
3616
  }
3553
- lockfileHelper.registerSourceData(bucketConfig.pathPattern, sourceData);
3617
+ lockfileHelper.registerSourceData(bucketPath.pathPattern, sourceData);
3554
3618
  }
3555
3619
  } catch (_error) {
3556
3620
  const error = new Error(`Failed to process bucket ${bucket.type}: ${_error.message}`);
@@ -3578,9 +3642,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3578
3642
  }
3579
3643
  });
3580
3644
  function calculateDataDelta(args) {
3581
- const newKeys = _19.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
3645
+ const newKeys = _20.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
3582
3646
  const updatedKeys = Object.keys(args.updatedSourceData);
3583
- const result = _19.chain(args.sourceData).pickBy((value, key) => newKeys.includes(key) || updatedKeys.includes(key)).value();
3647
+ const result = _20.chain(args.sourceData).pickBy((value, key) => newKeys.includes(key) || updatedKeys.includes(key)).value();
3584
3648
  return result;
3585
3649
  }
3586
3650
  async function retryWithExponentialBackoff(operation, maxAttempts, baseDelay = 1e3) {
@@ -3630,6 +3694,7 @@ function parseFlags(options) {
3630
3694
  verbose: Z4.boolean().optional(),
3631
3695
  strict: Z4.boolean().optional(),
3632
3696
  key: Z4.string().optional(),
3697
+ file: Z4.array(Z4.string()).optional(),
3633
3698
  interactive: Z4.boolean().default(false),
3634
3699
  debug: Z4.boolean().default(false)
3635
3700
  }).parse(options);
@@ -3725,7 +3790,7 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
3725
3790
  return args.currentData;
3726
3791
  }
3727
3792
  const customData = { ...args.currentData };
3728
- const changes = _19.reduce(
3793
+ const changes = _20.reduce(
3729
3794
  args.proposedData,
3730
3795
  (result, value, key) => {
3731
3796
  if (args.currentData[key] !== value) {
@@ -3788,7 +3853,7 @@ var lockfile_default = new Command7().command("lockfile").description("Create a
3788
3853
  const i18nConfig = getConfig();
3789
3854
  const buckets = getBuckets(i18nConfig);
3790
3855
  for (const bucket of buckets) {
3791
- for (const bucketConfig of bucket.config) {
3856
+ for (const bucketConfig of bucket.paths) {
3792
3857
  const sourceLocale = resolveOverriddenLocale4(i18nConfig.locale.source, bucketConfig.delimiter);
3793
3858
  const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
3794
3859
  isCacheRestore: false,
@@ -3809,9 +3874,12 @@ var flagsSchema = Z5.object({
3809
3874
  // src/cli/cmd/cleanup.ts
3810
3875
  import { resolveOverriddenLocale as resolveOverriddenLocale5 } from "@lingo.dev/_spec";
3811
3876
  import { Command as Command8 } from "interactive-commander";
3812
- import _20 from "lodash";
3877
+ import _21 from "lodash";
3813
3878
  import Ora7 from "ora";
3814
- var cleanup_default = new Command8().command("cleanup").description("Remove keys from target files that do not exist in the source file").helpOption("-h, --help", "Show help").option("--locale <locale>", "Specific locale to cleanup").option("--bucket <bucket>", "Specific bucket to cleanup").option("--dry-run", "Show what would be removed without making changes").option("--verbose", "Show detailed output including:\n - List of keys that would be removed.\n - Processing steps.").action(async function(options) {
3879
+ var cleanup_default = new Command8().command("cleanup").description("Remove keys from target files that do not exist in the source file").helpOption("-h, --help", "Show help").option("--locale <locale>", "Specific locale to cleanup").option("--bucket <bucket>", "Specific bucket to cleanup").option("--dry-run", "Show what would be removed without making changes").option(
3880
+ "--verbose",
3881
+ "Show detailed output including:\n - List of keys that would be removed.\n - Processing steps."
3882
+ ).action(async function(options) {
3815
3883
  const ora = Ora7();
3816
3884
  const results = [];
3817
3885
  try {
@@ -3827,7 +3895,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
3827
3895
  for (const bucket of buckets) {
3828
3896
  console.log();
3829
3897
  ora.info(`Processing bucket: ${bucket.type}`);
3830
- for (const bucketConfig of bucket.config) {
3898
+ for (const bucketConfig of bucket.paths) {
3831
3899
  const sourceLocale = resolveOverriddenLocale5(i18nConfig.locale.source, bucketConfig.delimiter);
3832
3900
  const bucketOra = Ora7({ indent: 2 }).info(`Processing path: ${bucketConfig.pathPattern}`);
3833
3901
  const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern, {
@@ -3842,7 +3910,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
3842
3910
  try {
3843
3911
  const targetData = await bucketLoader.pull(targetLocale);
3844
3912
  const targetKeys = Object.keys(targetData);
3845
- const keysToRemove = _20.difference(targetKeys, sourceKeys);
3913
+ const keysToRemove = _21.difference(targetKeys, sourceKeys);
3846
3914
  if (keysToRemove.length === 0) {
3847
3915
  bucketOra.succeed(`[${targetLocale}] No keys to remove`);
3848
3916
  continue;
@@ -3851,7 +3919,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
3851
3919
  bucketOra.info(`[${targetLocale}] Keys to remove: ${JSON.stringify(keysToRemove, null, 2)}`);
3852
3920
  }
3853
3921
  if (!options.dryRun) {
3854
- const cleanedData = _20.pick(targetData, sourceKeys);
3922
+ const cleanedData = _21.pick(targetData, sourceKeys);
3855
3923
  await bucketLoader.push(targetLocale, cleanedData);
3856
3924
  bucketOra.succeed(`[${targetLocale}] Removed ${keysToRemove.length} keys`);
3857
3925
  } else {
@@ -3906,7 +3974,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3906
3974
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3907
3975
  import Z6 from "zod";
3908
3976
  import { ReplexicaEngine } from "@lingo.dev/_sdk";
3909
- var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_21, program) => {
3977
+ var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_22, program) => {
3910
3978
  const apiKey = program.args[0];
3911
3979
  const settings = getSettings(apiKey);
3912
3980
  if (!settings.auth.apiKey) {
@@ -4101,35 +4169,21 @@ var PullRequestFlow = class extends InBranchFlow {
4101
4169
  this.ora.start(
4102
4170
  `Checking for existing PR with head ${i18nBranchName} and base ${this.platformKit.platformConfig.baseBranchName}`
4103
4171
  );
4104
- const existingPrNumber = await this.platformKit.getOpenPullRequestNumber({
4172
+ let prNumber = await this.platformKit.getOpenPullRequestNumber({
4105
4173
  branch: i18nBranchName
4106
4174
  });
4107
- this.ora.succeed(existingPrNumber ? "PR found" : "No PR found");
4108
- if (existingPrNumber) {
4109
- this.ora.start(`Closing existing PR ${existingPrNumber}`);
4110
- await this.platformKit.closePullRequest({
4111
- pullRequestNumber: existingPrNumber
4112
- });
4113
- this.ora.succeed(`Closed existing PR ${existingPrNumber}`);
4114
- }
4115
- this.ora.start(`Creating new PR`);
4116
- const newPrNumber = await this.platformKit.createPullRequest({
4117
- head: i18nBranchName,
4118
- title: this.platformKit.config.pullRequestTitle,
4119
- body: this.getPrBodyContent()
4120
- });
4121
- this.ora.succeed(`Created new PR ${newPrNumber}`);
4122
- if (existingPrNumber) {
4123
- this.ora.start(`Posting comment about outdated PR ${existingPrNumber}`);
4124
- await this.platformKit.commentOnPullRequest({
4125
- pullRequestNumber: existingPrNumber,
4126
- body: `This PR is now outdated. A new version has been created at ${this.platformKit.buildPullRequestUrl(
4127
- newPrNumber
4128
- )}`
4175
+ if (prNumber) {
4176
+ this.ora.succeed(`Existing PR found: #${prNumber}`);
4177
+ } else {
4178
+ this.ora.start(`Creating new PR`);
4179
+ prNumber = await this.platformKit.createPullRequest({
4180
+ head: i18nBranchName,
4181
+ title: this.platformKit.config.pullRequestTitle,
4182
+ body: this.getPrBodyContent()
4129
4183
  });
4130
- this.ora.succeed(`Posted comment about outdated PR ${existingPrNumber}`);
4184
+ this.ora.succeed(`Created new PR: #${prNumber}`);
4131
4185
  }
4132
- return newPrNumber;
4186
+ return prNumber;
4133
4187
  }
4134
4188
  checkoutI18nBranch(i18nBranchName) {
4135
4189
  execSync3(`git fetch origin ${i18nBranchName}`, { stdio: "inherit" });
@@ -4583,7 +4637,7 @@ var ci_default = new Command10().command("ci").description("Run Lingo.dev CI/CD
4583
4637
  // package.json
4584
4638
  var package_default = {
4585
4639
  name: "lingo.dev",
4586
- version: "0.79.0",
4640
+ version: "0.79.2",
4587
4641
  description: "Lingo.dev CLI",
4588
4642
  private: false,
4589
4643
  publishConfig: {