@intlayer/cli 9.7.1 → 9.7.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.
Files changed (92) hide show
  1. package/dist/cjs/_virtual/_utils_asset.cjs +1 -1
  2. package/dist/cjs/build.cjs +1 -1
  3. package/dist/cjs/bundle.cjs.map +1 -1
  4. package/dist/cjs/ci.cjs +1 -1
  5. package/dist/cjs/cli.cjs +5 -1
  6. package/dist/cjs/cli.cjs.map +1 -1
  7. package/dist/cjs/editor.cjs +2 -2
  8. package/dist/cjs/extract.cjs +4 -4
  9. package/dist/cjs/fill/fill.cjs +2 -2
  10. package/dist/cjs/fill/formatAutoFilledFilePath.cjs +1 -1
  11. package/dist/cjs/fill/listTranslationsTasks.cjs +2 -2
  12. package/dist/cjs/fill/translateDictionary.cjs +3 -3
  13. package/dist/cjs/fill/writeFill.cjs +2 -2
  14. package/dist/cjs/getTargetDictionary.cjs +2 -2
  15. package/dist/cjs/index.cjs +3 -2
  16. package/dist/cjs/init.cjs +20 -2
  17. package/dist/cjs/init.cjs.map +1 -1
  18. package/dist/cjs/initInfra.cjs +1 -1
  19. package/dist/cjs/listContentDeclaration.cjs +2 -2
  20. package/dist/cjs/listProjects.cjs +1 -1
  21. package/dist/cjs/liveSync.cjs +4 -4
  22. package/dist/cjs/pull.cjs +16 -7
  23. package/dist/cjs/pull.cjs.map +1 -1
  24. package/dist/cjs/push/push.cjs +4 -4
  25. package/dist/cjs/reviewDoc/reviewDoc.cjs +3 -3
  26. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +5 -5
  27. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
  28. package/dist/cjs/reviewDoc/reviewDocLog.cjs +2 -2
  29. package/dist/cjs/test/listMissingTranslations.cjs +1 -1
  30. package/dist/cjs/test/test.cjs +1 -1
  31. package/dist/cjs/translateDoc/translateDoc.cjs +2 -2
  32. package/dist/cjs/translateDoc/translateFile.cjs +4 -4
  33. package/dist/cjs/translateDoc/translateFile.cjs.map +1 -1
  34. package/dist/cjs/upgrade.cjs +1 -1
  35. package/dist/cjs/utils/checkAccess.cjs +1 -1
  36. package/dist/cjs/utils/detectGitRepository.cjs +1 -1
  37. package/dist/cjs/utils/getParentPackageJSON.cjs +1 -1
  38. package/dist/esm/_virtual/_utils_asset.mjs +1 -1
  39. package/dist/esm/build.mjs +1 -1
  40. package/dist/esm/bundle.mjs.map +1 -1
  41. package/dist/esm/ci.mjs +1 -1
  42. package/dist/esm/cli.mjs +5 -1
  43. package/dist/esm/cli.mjs.map +1 -1
  44. package/dist/esm/editor.mjs +2 -2
  45. package/dist/esm/extract.mjs +5 -5
  46. package/dist/esm/extract.mjs.map +1 -1
  47. package/dist/esm/fill/fill.mjs +4 -4
  48. package/dist/esm/fill/fill.mjs.map +1 -1
  49. package/dist/esm/fill/formatAutoFilledFilePath.mjs +1 -1
  50. package/dist/esm/fill/listTranslationsTasks.mjs +2 -2
  51. package/dist/esm/fill/translateDictionary.mjs +3 -3
  52. package/dist/esm/fill/writeFill.mjs +2 -2
  53. package/dist/esm/getTargetDictionary.mjs +2 -2
  54. package/dist/esm/index.mjs +4 -4
  55. package/dist/esm/init.mjs +20 -3
  56. package/dist/esm/init.mjs.map +1 -1
  57. package/dist/esm/initInfra.mjs +1 -1
  58. package/dist/esm/listContentDeclaration.mjs +2 -2
  59. package/dist/esm/listProjects.mjs +1 -1
  60. package/dist/esm/liveSync.mjs +3 -3
  61. package/dist/esm/pull.mjs +16 -7
  62. package/dist/esm/pull.mjs.map +1 -1
  63. package/dist/esm/push/push.mjs +6 -6
  64. package/dist/esm/push/push.mjs.map +1 -1
  65. package/dist/esm/reviewDoc/reviewDoc.mjs +3 -3
  66. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +5 -5
  67. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
  68. package/dist/esm/reviewDoc/reviewDocLog.mjs +2 -2
  69. package/dist/esm/test/listMissingTranslations.mjs +1 -1
  70. package/dist/esm/test/test.mjs +1 -1
  71. package/dist/esm/translateDoc/translateDoc.mjs +2 -2
  72. package/dist/esm/translateDoc/translateFile.mjs +4 -4
  73. package/dist/esm/translateDoc/translateFile.mjs.map +1 -1
  74. package/dist/esm/upgrade.mjs +1 -1
  75. package/dist/esm/utils/checkAccess.mjs +1 -1
  76. package/dist/esm/utils/detectGitRepository.mjs +1 -1
  77. package/dist/esm/utils/getParentPackageJSON.mjs +1 -1
  78. package/dist/types/IntlayerEventListener.d.ts +1 -1
  79. package/dist/types/bundle.d.ts.map +1 -1
  80. package/dist/types/fill/fill.d.ts +1 -1
  81. package/dist/types/fill/formatAutoFilledFilePath.d.ts +1 -1
  82. package/dist/types/index.d.ts +3 -3
  83. package/dist/types/init.d.ts +5 -1
  84. package/dist/types/init.d.ts.map +1 -1
  85. package/dist/types/pull.d.ts +14 -1
  86. package/dist/types/pull.d.ts.map +1 -1
  87. package/dist/types/reviewDoc/reviewDoc.d.ts +1 -1
  88. package/dist/types/test/listMissingTranslations.d.ts +1 -1
  89. package/dist/types/translateDoc/types.d.ts +2 -2
  90. package/dist/types/utils/checkAccess.d.ts +1 -1
  91. package/dist/types/utils/selectCmsEnvironment.d.ts +1 -1
  92. package/package.json +33 -33
@@ -2,16 +2,16 @@ import { loadPrompts } from "../loadPrompts.mjs";
2
2
  import { PushLogger } from "../pushLog.mjs";
3
3
  import { checkCMSAuth, getAuthenticatedAPI } from "../utils/checkAccess.mjs";
4
4
  import { selectCmsEnvironment } from "../utils/selectCmsEnvironment.mjs";
5
+ import { join } from "node:path";
5
6
  import * as ANSIColors from "@intlayer/config/colors";
6
7
  import { colorize, colorizeKey, getAppLogger } from "@intlayer/config/logger";
7
8
  import { getConfiguration } from "@intlayer/config/node";
9
+ import { getUnmergedDictionaries } from "@intlayer/dictionaries-entry/unmerged";
10
+ import { prepareIntlayer, writeContentDeclaration } from "@intlayer/engine/build";
8
11
  import { listGitFiles, logConfigDetails } from "@intlayer/engine/cli";
9
- import { join } from "node:path";
10
- import * as fsPromises from "node:fs/promises";
11
12
  import { formatPath } from "@intlayer/engine/utils";
13
+ import * as fsPromises from "node:fs/promises";
12
14
  import { parallelize } from "@intlayer/config/utils";
13
- import { getUnmergedDictionaries } from "@intlayer/dictionaries-entry/unmerged";
14
- import { prepareIntlayer as prepareIntlayer$1, writeContentDeclaration } from "@intlayer/engine/build";
15
15
 
16
16
  // src/push/push.ts
17
17
  const statusIconsAndColors = {
@@ -46,8 +46,8 @@ const push = async (options) => {
46
46
  const config = getConfiguration(options?.configOptions);
47
47
  logConfigDetails(options?.configOptions);
48
48
  const appLogger = getAppLogger(config);
49
- if (options?.build === true) await prepareIntlayer$1(config, { forceRun: true });
50
- else if (typeof options?.build === "undefined") await prepareIntlayer$1(config);
49
+ if (options?.build === true) await prepareIntlayer(config, { forceRun: true });
50
+ else if (typeof options?.build === "undefined") await prepareIntlayer(config);
51
51
  try {
52
52
  if (!await checkCMSAuth(config)) return;
53
53
  const intlayerAPI = await getAuthenticatedAPI(config);
@@ -1 +1 @@
1
- {"version":3,"file":"push.mjs","names":["prepareIntlayer"],"sources":["../../../src/push/push.ts"],"sourcesContent":["import * as fsPromises from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { parallelize } from '@intlayer/config/utils';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport {\n prepareIntlayer,\n writeContentDeclaration,\n} from '@intlayer/engine/build';\nimport {\n type ListGitFilesOptions,\n listGitFiles,\n logConfigDetails,\n} from '@intlayer/engine/cli';\nimport { formatPath } from '@intlayer/engine/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { loadPrompts } from '../loadPrompts';\nimport { PushLogger, type PushStatus } from '../pushLog';\nimport { checkCMSAuth, getAuthenticatedAPI } from '../utils/checkAccess';\nimport { selectCmsEnvironment } from '../utils/selectCmsEnvironment';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n build?: boolean;\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status:\n | 'pending'\n | 'pushing'\n | 'modified'\n | 'pushed'\n | 'up-to-date'\n | 'unknown'\n | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n// Print per-dictionary summary similar to loadDictionaries\nconst statusIconsAndColors = {\n pushed: { icon: '✔', color: ANSIColors.GREEN },\n modified: { icon: '✔', color: ANSIColors.GREEN },\n 'up-to-date': { icon: '=', color: ANSIColors.GREY },\n error: { icon: '✖', color: ANSIColors.RED },\n default: { icon: '⏲', color: ANSIColors.BLUE },\n};\n\nconst getIconAndColor = (status: DictionariesStatus['status']) => {\n return (\n statusIconsAndColors[status as keyof typeof statusIconsAndColors] ??\n statusIconsAndColors.default\n );\n};\n\n/**\n * Get all local dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const appLogger = getAppLogger(config);\n\n if (options?.build === true) {\n await prepareIntlayer(config, { forceRun: true });\n } else if (typeof options?.build === 'undefined') {\n await prepareIntlayer(config);\n }\n\n try {\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = await getAuthenticatedAPI(config);\n\n await selectCmsEnvironment(\n options?.configOptions?.env,\n intlayerAPI,\n config\n );\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n const allDictionaries = Object.values(unmergedDictionariesRecord).flat();\n\n const customLocations = Array.from(\n new Set(\n allDictionaries\n .map((dictionary) => dictionary.location)\n .filter(\n (location) =>\n location && !['remote', 'local', 'hybrid'].includes(location)\n )\n )\n ) as string[];\n\n // Include all custom locations automatically — no interactive prompt needed.\n const selectedCustomLocations: string[] = customLocations;\n\n let dictionaries: Dictionary[] = allDictionaries.filter((dictionary) => {\n const location =\n dictionary.location ?? config.dictionary?.location ?? 'local';\n\n return (\n location === 'remote' ||\n location === 'hybrid' ||\n selectedCustomLocations.includes(location)\n );\n });\n\n // Check if the dictionaries list is empty after filtering by location\n if (dictionaries.length === 0) {\n appLogger(\n `No dictionaries found to push. Only dictionaries with location ${colorize('remote', ANSIColors.BLUE, ANSIColors.RESET)}, ${colorize('hybrid', ANSIColors.BLUE, ANSIColors.RESET)} or selected custom locations are pushed.`,\n { level: 'warn' }\n );\n appLogger(\n `You can set the location in your dictionary file (e.g. ${colorize(\"{ key: 'my-key', location: 'hybrid', ... }\", ANSIColors.BLUE, ANSIColors.RESET)} or globally in your intlayer.config.ts file (e.g. ${colorize(\"{ dictionary: { location: 'hybrid' } }\", ANSIColors.BLUE, ANSIColors.RESET)}).`,\n { level: 'info' }\n );\n return;\n }\n\n const existingDictionariesKeys: string[] = Object.keys(\n unmergedDictionariesRecord\n );\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n appLogger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n {\n level: 'error',\n }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries?.includes(dictionary.key)\n );\n }\n\n if (options?.gitOptions) {\n const gitFiles = await listGitFiles(options.gitOptions);\n\n dictionaries = dictionaries.filter((dictionary) =>\n gitFiles.includes(\n join(config.system.baseDir, dictionary.filePath ?? '')\n )\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n appLogger('No local dictionaries found', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary) => ({\n dictionary,\n status: 'pending',\n })\n );\n\n // Initialize aggregated logger similar to loadDictionaries\n const logger = new PushLogger();\n logger.update(\n dictionariesStatuses.map<PushStatus>((s) => ({\n dictionaryKey: s.dictionary.key,\n status: 'pending',\n }))\n );\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushing' },\n ]);\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries([\n statusObj.dictionary,\n ]);\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries ?? [];\n const newDictionaries = pushResult.data?.newDictionaries ?? [];\n const upToDateDictionaries =\n pushResult.data?.upToDateDictionaries ?? [];\n\n const allDictionaries = [\n ...updatedDictionaries,\n ...newDictionaries,\n ...upToDateDictionaries,\n ];\n\n for (const remoteDictionaryData of allDictionaries) {\n const localDictionary = unmergedDictionariesRecord[\n remoteDictionaryData.key\n ]?.find(\n (dictionary) => dictionary.localId === remoteDictionaryData.localId\n );\n\n if (!localDictionary) continue;\n\n await writeContentDeclaration(\n { ...localDictionary, id: remoteDictionaryData.id },\n config\n );\n }\n\n if (\n updatedDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'modified' },\n ]);\n } else if (\n newDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushed' },\n ]);\n } else if (\n upToDateDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'up-to-date';\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'up-to-date' },\n ]);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit (reuse parallelize)\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n for (const dictionaryStatus of dictionariesStatuses) {\n const { icon, color } = getIconAndColor(dictionaryStatus.status);\n appLogger(\n ` - ${colorizeKey(dictionaryStatus.dictionary.key)} ${ANSIColors.GREY}[${color}${icon} ${dictionaryStatus.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries, options);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const remoteDictionaries = successfullyPushedDictionaries.filter(\n (dictionary) => dictionary.location === 'remote'\n );\n const remoteDictionariesKeys = remoteDictionaries.map(\n (dictionary) => dictionary.key\n );\n\n if (remoteDictionaries.length > 0) {\n const { confirm, isCancel } = await loadPrompts();\n\n const shouldDelete = await confirm({\n message: `Do you want to delete the local dictionaries that were successfully pushed? ${colorize('(Dictionaries:', ANSIColors.GREY, ANSIColors.RESET)} ${colorizeKey(remoteDictionariesKeys)}${colorize(')', ANSIColors.GREY, ANSIColors.RESET)}`,\n initialValue: false,\n });\n\n if (isCancel(shouldDelete)) {\n return;\n }\n\n if (shouldDelete) {\n await deleteLocalDictionaries(remoteDictionaries, options);\n }\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[],\n options?: PushOptions\n): Promise<void> => {\n const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config);\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n appLogger(\n `Dictionary ${colorizeKey(dictionary.key)} does not have a file path`,\n {\n level: 'error',\n }\n );\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n appLogger(`Deleted file ${formatPath(filePath)}`, {});\n } else if (stats.isDirectory()) {\n appLogger(`Path is a directory ${formatPath(filePath)}, skipping.`, {});\n } else {\n appLogger(\n `Unknown file type for ${formatPath(filePath)}, skipping.`,\n {}\n );\n }\n } catch (err) {\n appLogger(`Error deleting ${formatPath(filePath)}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"push.mjs","names":[],"sources":["../../../src/push/push.ts"],"sourcesContent":["import * as fsPromises from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { parallelize } from '@intlayer/config/utils';\nimport { getUnmergedDictionaries } from '@intlayer/dictionaries-entry/unmerged';\nimport {\n prepareIntlayer,\n writeContentDeclaration,\n} from '@intlayer/engine/build';\nimport {\n type ListGitFilesOptions,\n listGitFiles,\n logConfigDetails,\n} from '@intlayer/engine/cli';\nimport { formatPath } from '@intlayer/engine/utils';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { loadPrompts } from '../loadPrompts';\nimport { PushLogger, type PushStatus } from '../pushLog';\nimport { checkCMSAuth, getAuthenticatedAPI } from '../utils/checkAccess';\nimport { selectCmsEnvironment } from '../utils/selectCmsEnvironment';\n\ntype PushOptions = {\n deleteLocaleDictionary?: boolean;\n keepLocaleDictionary?: boolean;\n dictionaries?: string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n build?: boolean;\n};\n\ntype DictionariesStatus = {\n dictionary: Dictionary;\n status:\n | 'pending'\n | 'pushing'\n | 'modified'\n | 'pushed'\n | 'up-to-date'\n | 'unknown'\n | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n// Print per-dictionary summary similar to loadDictionaries\nconst statusIconsAndColors = {\n pushed: { icon: '✔', color: ANSIColors.GREEN },\n modified: { icon: '✔', color: ANSIColors.GREEN },\n 'up-to-date': { icon: '=', color: ANSIColors.GREY },\n error: { icon: '✖', color: ANSIColors.RED },\n default: { icon: '⏲', color: ANSIColors.BLUE },\n};\n\nconst getIconAndColor = (status: DictionariesStatus['status']) => {\n return (\n statusIconsAndColors[status as keyof typeof statusIconsAndColors] ??\n statusIconsAndColors.default\n );\n};\n\n/**\n * Get all local dictionaries and push them simultaneously.\n */\nexport const push = async (options?: PushOptions): Promise<void> => {\n const config = getConfiguration(options?.configOptions);\n logConfigDetails(options?.configOptions);\n\n const appLogger = getAppLogger(config);\n\n if (options?.build === true) {\n await prepareIntlayer(config, { forceRun: true });\n } else if (typeof options?.build === 'undefined') {\n await prepareIntlayer(config);\n }\n\n try {\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = await getAuthenticatedAPI(config);\n\n await selectCmsEnvironment(\n options?.configOptions?.env,\n intlayerAPI,\n config\n );\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n const allDictionaries = Object.values(unmergedDictionariesRecord).flat();\n\n const customLocations = Array.from(\n new Set(\n allDictionaries\n .map((dictionary) => dictionary.location)\n .filter(\n (location) =>\n location && !['remote', 'local', 'hybrid'].includes(location)\n )\n )\n ) as string[];\n\n // Include all custom locations automatically — no interactive prompt needed.\n const selectedCustomLocations: string[] = customLocations;\n\n let dictionaries: Dictionary[] = allDictionaries.filter((dictionary) => {\n const location =\n dictionary.location ?? config.dictionary?.location ?? 'local';\n\n return (\n location === 'remote' ||\n location === 'hybrid' ||\n selectedCustomLocations.includes(location)\n );\n });\n\n // Check if the dictionaries list is empty after filtering by location\n if (dictionaries.length === 0) {\n appLogger(\n `No dictionaries found to push. Only dictionaries with location ${colorize('remote', ANSIColors.BLUE, ANSIColors.RESET)}, ${colorize('hybrid', ANSIColors.BLUE, ANSIColors.RESET)} or selected custom locations are pushed.`,\n { level: 'warn' }\n );\n appLogger(\n `You can set the location in your dictionary file (e.g. ${colorize(\"{ key: 'my-key', location: 'hybrid', ... }\", ANSIColors.BLUE, ANSIColors.RESET)} or globally in your intlayer.config.ts file (e.g. ${colorize(\"{ dictionary: { location: 'hybrid' } }\", ANSIColors.BLUE, ANSIColors.RESET)}).`,\n { level: 'info' }\n );\n return;\n }\n\n const existingDictionariesKeys: string[] = Object.keys(\n unmergedDictionariesRecord\n );\n\n if (options?.dictionaries) {\n // Check if the provided dictionaries exist\n const noneExistingDictionariesOption = options.dictionaries.filter(\n (dictionaryId) => !existingDictionariesKeys.includes(dictionaryId)\n );\n\n if (noneExistingDictionariesOption.length > 0) {\n appLogger(\n `The following dictionaries do not exist: ${noneExistingDictionariesOption.join(\n ', '\n )} and have been ignored.`,\n {\n level: 'error',\n }\n );\n }\n\n // Filter the dictionaries from the provided list of IDs\n dictionaries = dictionaries.filter((dictionary) =>\n options.dictionaries?.includes(dictionary.key)\n );\n }\n\n if (options?.gitOptions) {\n const gitFiles = await listGitFiles(options.gitOptions);\n\n dictionaries = dictionaries.filter((dictionary) =>\n gitFiles.includes(\n join(config.system.baseDir, dictionary.filePath ?? '')\n )\n );\n }\n\n // Check if the dictionaries list is empty\n if (dictionaries.length === 0) {\n appLogger('No local dictionaries found', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Pushing dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = dictionaries.map(\n (dictionary) => ({\n dictionary,\n status: 'pending',\n })\n );\n\n // Initialize aggregated logger similar to loadDictionaries\n const logger = new PushLogger();\n logger.update(\n dictionariesStatuses.map<PushStatus>((s) => ({\n dictionaryKey: s.dictionary.key,\n status: 'pending',\n }))\n );\n\n const successfullyPushedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n statusObj.status = 'pushing';\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushing' },\n ]);\n\n try {\n const pushResult = await intlayerAPI.dictionary.pushDictionaries([\n statusObj.dictionary,\n ]);\n\n const updatedDictionaries = pushResult.data?.updatedDictionaries ?? [];\n const newDictionaries = pushResult.data?.newDictionaries ?? [];\n const upToDateDictionaries =\n pushResult.data?.upToDateDictionaries ?? [];\n\n const allDictionaries = [\n ...updatedDictionaries,\n ...newDictionaries,\n ...upToDateDictionaries,\n ];\n\n for (const remoteDictionaryData of allDictionaries) {\n const localDictionary = unmergedDictionariesRecord[\n remoteDictionaryData.key\n ]?.find(\n (dictionary) => dictionary.localId === remoteDictionaryData.localId\n );\n\n if (!localDictionary) continue;\n\n await writeContentDeclaration(\n { ...localDictionary, id: remoteDictionaryData.id },\n config\n );\n }\n\n if (\n updatedDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'modified';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'modified' },\n ]);\n } else if (\n newDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'pushed';\n successfullyPushedDictionaries.push(statusObj.dictionary);\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'pushed' },\n ]);\n } else if (\n upToDateDictionaries.some(\n (dictionary) => dictionary.key === statusObj.dictionary.key\n )\n ) {\n statusObj.status = 'up-to-date';\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'up-to-date' },\n ]);\n } else {\n statusObj.status = 'unknown';\n }\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error pushing dictionary ${statusObj.dictionary.key}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionary.key, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with a concurrency limit (reuse parallelize)\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n for (const dictionaryStatus of dictionariesStatuses) {\n const { icon, color } = getIconAndColor(dictionaryStatus.status);\n appLogger(\n ` - ${colorizeKey(dictionaryStatus.dictionary.key)} ${ANSIColors.GREY}[${color}${icon} ${dictionaryStatus.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n\n // Handle delete or keep options\n const deleteOption = options?.deleteLocaleDictionary;\n const keepOption = options?.keepLocaleDictionary;\n\n if (deleteOption && keepOption) {\n throw new Error(\n 'Cannot specify both --deleteLocaleDictionary and --keepLocaleDictionary options.'\n );\n }\n\n if (deleteOption) {\n // Delete only the successfully pushed dictionaries\n await deleteLocalDictionaries(successfullyPushedDictionaries, options);\n } else if (keepOption) {\n // Do nothing, keep the local dictionaries\n } else {\n // Ask the user\n const remoteDictionaries = successfullyPushedDictionaries.filter(\n (dictionary) => dictionary.location === 'remote'\n );\n const remoteDictionariesKeys = remoteDictionaries.map(\n (dictionary) => dictionary.key\n );\n\n if (remoteDictionaries.length > 0) {\n const { confirm, isCancel } = await loadPrompts();\n\n const shouldDelete = await confirm({\n message: `Do you want to delete the local dictionaries that were successfully pushed? ${colorize('(Dictionaries:', ANSIColors.GREY, ANSIColors.RESET)} ${colorizeKey(remoteDictionariesKeys)}${colorize(')', ANSIColors.GREY, ANSIColors.RESET)}`,\n initialValue: false,\n });\n\n if (isCancel(shouldDelete)) {\n return;\n }\n\n if (shouldDelete) {\n await deleteLocalDictionaries(remoteDictionaries, options);\n }\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n\nconst deleteLocalDictionaries = async (\n dictionariesToDelete: Dictionary[],\n options?: PushOptions\n): Promise<void> => {\n const config = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(config);\n\n // Use a Set to collect all unique file paths\n const filePathsSet: Set<string> = new Set();\n\n for (const dictionary of dictionariesToDelete) {\n const { filePath } = dictionary;\n\n if (!filePath) {\n appLogger(\n `Dictionary ${colorizeKey(dictionary.key)} does not have a file path`,\n {\n level: 'error',\n }\n );\n continue;\n }\n\n filePathsSet.add(filePath);\n }\n\n for (const filePath of filePathsSet) {\n try {\n const stats = await fsPromises.lstat(filePath);\n\n if (stats.isFile()) {\n await fsPromises.unlink(filePath);\n appLogger(`Deleted file ${formatPath(filePath)}`, {});\n } else if (stats.isDirectory()) {\n appLogger(`Path is a directory ${formatPath(filePath)}, skipping.`, {});\n } else {\n appLogger(\n `Unknown file type for ${formatPath(filePath)}, skipping.`,\n {}\n );\n }\n } catch (err) {\n appLogger(`Error deleting ${formatPath(filePath)}: ${err}`, {\n level: 'error',\n });\n }\n }\n};\n"],"mappings":"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"}
@@ -6,14 +6,14 @@ import { reviewFileBlockAware } from "./reviewDocBlockAware.mjs";
6
6
  import { buildFileReviewReport, logReviewFileBlocks } from "./reviewDocLog.mjs";
7
7
  import { createReviewProgressLogger } from "./reviewDocProgress.mjs";
8
8
  import { formatReviewSynthesis } from "./reviewDocSynthesis.mjs";
9
+ import { existsSync } from "node:fs";
10
+ import { join, relative } from "node:path";
9
11
  import * as ANSIColors from "@intlayer/config/colors";
10
12
  import { colorize, colorizeNumber, getAppLogger, x } from "@intlayer/config/logger";
11
13
  import { getConfiguration } from "@intlayer/config/node";
12
14
  import { listGitFiles, listGitLines, logConfigDetails } from "@intlayer/engine/cli";
13
- import { join, relative } from "node:path";
14
- import { existsSync } from "node:fs";
15
- import { readFile } from "node:fs/promises";
16
15
  import { formatLocale, formatPath } from "@intlayer/engine/utils";
16
+ import { readFile } from "node:fs/promises";
17
17
  import { parallelize } from "@intlayer/config/utils";
18
18
  import { buildReviewReport } from "@intlayer/engine/docReview";
19
19
  import fg from "fast-glob";
@@ -2,13 +2,13 @@ import { readAsset } from "../_virtual/_utils_asset.mjs";
2
2
  import { sanitizeChunk, validateTranslation } from "../translateDoc/validation.mjs";
3
3
  import { chunkInference } from "../utils/chunkInference.mjs";
4
4
  import { fixChunkStartEndChars } from "../utils/fixChunkStartEndChars.mjs";
5
+ import { mkdirSync, writeFileSync } from "node:fs";
6
+ import { dirname } from "node:path";
5
7
  import * as ANSIColors from "@intlayer/config/colors";
6
8
  import { colon, colorize, colorizeNumber, getAppLogger } from "@intlayer/config/logger";
7
9
  import { getConfiguration } from "@intlayer/config/node";
8
- import { dirname } from "node:path";
9
- import { mkdirSync, writeFileSync } from "node:fs";
10
- import { readFile } from "node:fs/promises";
11
10
  import { formatLocale, formatPath } from "@intlayer/engine/utils";
11
+ import { readFile } from "node:fs/promises";
12
12
  import { retryManager } from "@intlayer/config/utils";
13
13
  import { buildAlignmentPlan, mergeReviewedSegments } from "@intlayer/engine/docReview";
14
14
  import { getLocaleName } from "@intlayer/core/localization";
@@ -83,8 +83,8 @@ const reviewFileBlockAware = async (baseFilePath, outputFilePath, locale, baseLo
83
83
  })).reverse();
84
84
  for (const { segment, displayNumber } of segmentsBottomUp) {
85
85
  const baseBlock = segment.baseBlock;
86
- const getBaseChunkContextPrompt = () => `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the base block in ${formatLocale(baseLocale, false)} as reference.\n///chunksStart///\n` + baseBlock.content + `///chunksEnd///`;
87
- const getTargetChunkPrompt = () => `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the current block to review in ${formatLocale(locale, false)}.\n///chunksStart///\n` + (segment.targetBlockText ?? "") + `///chunksEnd///`;
86
+ const getBaseChunkContextPrompt = () => `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the base block in ${formatLocale(baseLocale, false)} as reference.\n///chunksStart///\n${baseBlock.content}///chunksEnd///`;
87
+ const getTargetChunkPrompt = () => `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the current block to review in ${formatLocale(locale, false)}.\n///chunksStart///\n${segment.targetBlockText ?? ""}///chunksEnd///`;
88
88
  const reviewedChunkResult = await retryManager(async () => {
89
89
  const result = await chunkInference([
90
90
  {
@@ -1 +1 @@
1
- {"version":3,"file":"reviewDocBlockAware.mjs","names":[],"sources":["../../../src/reviewDoc/reviewDocBlockAware.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport type { AIConfig, AIOptions } from '@intlayer/ai';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { retryManager } from '@intlayer/config/utils';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport {\n buildAlignmentPlan,\n mergeReviewedSegments,\n type PlannedAction,\n type ReviewReportSummary,\n} from '@intlayer/engine/docReview';\nimport { formatLocale, formatPath } from '@intlayer/engine/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport { sanitizeChunk, validateTranslation } from '../translateDoc/validation';\nimport { chunkInference } from '../utils/chunkInference';\nimport { fixChunkStartEndChars } from '../utils/fixChunkStartEndChars';\nimport type { AIClient } from '../utils/setupAI';\n\n/**\n * Review a file using block-aware alignment.\n *\n * 1. Segments both base and target documents into semantic blocks.\n * 2. Aligns blocks using structure (special chars, numbers) and context.\n * 3. Detects which blocks changed, were added, or deleted.\n * 4. Applies deletions immediately without AI.\n * 5. Sends changed/new blocks to AI in bottom-up order (last block first), so\n * line numbers of earlier blocks are not shifted by edits below them.\n * 6. Rewrites the file after each block so progress is persisted incrementally.\n *\n * @returns The per-action block counts of the alignment plan, so the caller can\n * synthesize what was reused and what had to be edited.\n */\nexport const reviewFileBlockAware = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locale,\n baseLocale: Locale,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n customInstructions?: string,\n changedLines?: number[],\n aiClient?: AIClient,\n aiConfig?: AIConfig\n): Promise<ReviewReportSummary> => {\n const configuration = getConfiguration(configOptions);\n const applicationLogger = getAppLogger({\n log: { ...configuration.log, prefix: '' },\n });\n\n const baseText = await readFile(baseFilePath, 'utf-8');\n const targetText = await readFile(outputFilePath, 'utf-8').catch(() => '');\n\n const basePrompt = readAsset('./prompts/REVIEW_PROMPT.md', 'utf-8')\n .replaceAll('{{localeName}}', `${formatLocale(locale, false)}`)\n .replaceAll('{{baseLocaleName}}', `${formatLocale(baseLocale, false)}`)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const filePrefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}] `;\n const filePrefix = [\n colon(filePrefixText, { colSize: 40 }),\n `→ ${ANSIColors.RESET}`,\n ].join('');\n const prefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}][${formatLocale(locale)}${ANSIColors.GREY_DARK}] `;\n const prefix = [\n colon(prefixText, { colSize: 40 }),\n `→ ${ANSIColors.RESET}`,\n ].join('');\n\n // Build block-aware alignment and plan\n const { baseBlocks, targetBlocks, plan, segmentsToReview } =\n buildAlignmentPlan({\n baseText,\n targetText,\n changedLines,\n });\n\n const countActions = (kind: PlannedAction['kind']): number =>\n plan.actions.filter((action: PlannedAction) => action.kind === kind).length;\n\n const reviewSummary: ReviewReportSummary = {\n reuse: countActions('reuse'),\n review: countActions('review'),\n insertNew: countActions('insert_new'),\n delete: countActions('delete'),\n };\n\n const deleteCount = reviewSummary.delete;\n\n applicationLogger(\n `${filePrefix}Block-aware alignment complete. Total blocks: base=${colorizeNumber(baseBlocks.length)}, target=${colorizeNumber(targetBlocks.length)}`\n );\n applicationLogger(\n `${filePrefix}Actions: reuse=${colorizeNumber(reviewSummary.reuse)}, review=${colorizeNumber(reviewSummary.review)}, new=${colorizeNumber(reviewSummary.insertNew)}, delete=${colorizeNumber(deleteCount)}`\n );\n\n // Map shared across the entire run: each entry overrides the default behavior\n // of mergeReviewedSegments for that action index.\n const reviewedSegmentsMap = new Map<number, string>();\n\n // --- Step 1: apply deletions immediately (no AI needed) ---\n for (const [actionIndex, action] of plan.actions.entries()) {\n if (action.kind === 'delete') {\n reviewedSegmentsMap.set(actionIndex, '');\n }\n }\n\n const writeCurrentState = (): void => {\n const output = mergeReviewedSegments(\n plan,\n targetBlocks,\n reviewedSegmentsMap\n );\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, output);\n };\n\n if (deleteCount > 0) {\n writeCurrentState();\n applicationLogger(\n `${filePrefix}${colorizeNumber(deleteCount)} block(s) deleted without AI.`\n );\n }\n\n if (segmentsToReview.length === 0) {\n if (deleteCount === 0) {\n applicationLogger(\n `${filePrefix}No segments need review, reusing existing translation`\n );\n writeCurrentState();\n }\n applicationLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(outputFilePath)} updated successfully (no changes needed).`\n );\n return reviewSummary;\n }\n\n applicationLogger(\n `${filePrefix}Segments to review: ${colorizeNumber(segmentsToReview.length)} (processing bottom-up)`\n );\n\n // --- Step 2: process AI segments in bottom-up order ---\n // Reversing ensures edits near the end of the file don't shift line numbers\n // that matter for blocks higher up, and each intermediate file write is valid.\n const segmentsBottomUp = segmentsToReview\n .map((segment, originalIndex) => ({\n segment,\n displayNumber: originalIndex + 1,\n }))\n .reverse();\n\n for (const { segment, displayNumber } of segmentsBottomUp) {\n const baseBlock = segment.baseBlock;\n\n const getBaseChunkContextPrompt = () =>\n `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the base block in ${formatLocale(baseLocale, false)} as reference.\\n` +\n `///chunksStart///\\n` +\n baseBlock.content +\n `///chunksEnd///`;\n\n const getTargetChunkPrompt = () =>\n `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the current block to review in ${formatLocale(locale, false)}.\\n` +\n `///chunksStart///\\n` +\n (segment.targetBlockText ?? '') +\n `///chunksEnd///`;\n\n const reviewedChunkResult = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n { role: 'system', content: getBaseChunkContextPrompt() },\n { role: 'system', content: getTargetChunkPrompt() },\n {\n role: 'system',\n content: `The next user message will be the **BLOCK ${colorizeNumber(displayNumber)} of ${colorizeNumber(segmentsToReview.length)}** that should be translated in ${getLocaleName(locale, ENGLISH)} (${locale}).`,\n },\n ],\n [{ role: 'user', content: baseBlock.content }],\n aiOptions,\n configuration,\n aiClient,\n aiConfig\n );\n\n applicationLogger(\n `${prefix}${colorizeNumber(result.tokenUsed)} tokens used - Block ${colorizeNumber(displayNumber)} of ${colorizeNumber(segmentsToReview.length)}`\n );\n\n let processedChunk = sanitizeChunk(\n result?.fileContent,\n baseBlock.content\n );\n processedChunk = fixChunkStartEndChars(processedChunk, baseBlock.content);\n\n const isValid = validateTranslation(\n baseBlock.content,\n processedChunk,\n applicationLogger\n );\n\n if (!isValid) {\n throw new Error(\n 'Validation failed for chunk (structure or length mismatch). Retrying...'\n );\n }\n\n return processedChunk;\n })();\n\n reviewedSegmentsMap.set(segment.actionIndex, reviewedChunkResult);\n\n // Rewrite the file after every block so progress is never lost.\n writeCurrentState();\n }\n\n applicationLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(outputFilePath)} created/updated successfully.`\n );\n\n return reviewSummary;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"reviewDocBlockAware.mjs","names":[],"sources":["../../../src/reviewDoc/reviewDocBlockAware.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { AIConfig, AIOptions } from '@intlayer/ai';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { retryManager } from '@intlayer/config/utils';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport {\n buildAlignmentPlan,\n mergeReviewedSegments,\n type PlannedAction,\n type ReviewReportSummary,\n} from '@intlayer/engine/docReview';\nimport { formatLocale, formatPath } from '@intlayer/engine/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport { readAsset } from 'utils:asset';\nimport { sanitizeChunk, validateTranslation } from '../translateDoc/validation';\nimport { chunkInference } from '../utils/chunkInference';\nimport { fixChunkStartEndChars } from '../utils/fixChunkStartEndChars';\nimport type { AIClient } from '../utils/setupAI';\n\n/**\n * Review a file using block-aware alignment.\n *\n * 1. Segments both base and target documents into semantic blocks.\n * 2. Aligns blocks using structure (special chars, numbers) and context.\n * 3. Detects which blocks changed, were added, or deleted.\n * 4. Applies deletions immediately without AI.\n * 5. Sends changed/new blocks to AI in bottom-up order (last block first), so\n * line numbers of earlier blocks are not shifted by edits below them.\n * 6. Rewrites the file after each block so progress is persisted incrementally.\n *\n * @returns The per-action block counts of the alignment plan, so the caller can\n * synthesize what was reused and what had to be edited.\n */\nexport const reviewFileBlockAware = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locale,\n baseLocale: Locale,\n aiOptions?: AIOptions,\n configOptions?: GetConfigurationOptions,\n customInstructions?: string,\n changedLines?: number[],\n aiClient?: AIClient,\n aiConfig?: AIConfig\n): Promise<ReviewReportSummary> => {\n const configuration = getConfiguration(configOptions);\n const applicationLogger = getAppLogger({\n log: { ...configuration.log, prefix: '' },\n });\n\n const baseText = await readFile(baseFilePath, 'utf-8');\n const targetText = await readFile(outputFilePath, 'utf-8').catch(() => '');\n\n const basePrompt = readAsset('./prompts/REVIEW_PROMPT.md', 'utf-8')\n .replaceAll('{{localeName}}', `${formatLocale(locale, false)}`)\n .replaceAll('{{baseLocaleName}}', `${formatLocale(baseLocale, false)}`)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const filePrefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}] `;\n const filePrefix = [\n colon(filePrefixText, { colSize: 40 }),\n `→ ${ANSIColors.RESET}`,\n ].join('');\n const prefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}][${formatLocale(locale)}${ANSIColors.GREY_DARK}] `;\n const prefix = [\n colon(prefixText, { colSize: 40 }),\n `→ ${ANSIColors.RESET}`,\n ].join('');\n\n // Build block-aware alignment and plan\n const { baseBlocks, targetBlocks, plan, segmentsToReview } =\n buildAlignmentPlan({\n baseText,\n targetText,\n changedLines,\n });\n\n const countActions = (kind: PlannedAction['kind']): number =>\n plan.actions.filter((action: PlannedAction) => action.kind === kind).length;\n\n const reviewSummary: ReviewReportSummary = {\n reuse: countActions('reuse'),\n review: countActions('review'),\n insertNew: countActions('insert_new'),\n delete: countActions('delete'),\n };\n\n const deleteCount = reviewSummary.delete;\n\n applicationLogger(\n `${filePrefix}Block-aware alignment complete. Total blocks: base=${colorizeNumber(baseBlocks.length)}, target=${colorizeNumber(targetBlocks.length)}`\n );\n applicationLogger(\n `${filePrefix}Actions: reuse=${colorizeNumber(reviewSummary.reuse)}, review=${colorizeNumber(reviewSummary.review)}, new=${colorizeNumber(reviewSummary.insertNew)}, delete=${colorizeNumber(deleteCount)}`\n );\n\n // Map shared across the entire run: each entry overrides the default behavior\n // of mergeReviewedSegments for that action index.\n const reviewedSegmentsMap = new Map<number, string>();\n\n // --- Step 1: apply deletions immediately (no AI needed) ---\n for (const [actionIndex, action] of plan.actions.entries()) {\n if (action.kind === 'delete') {\n reviewedSegmentsMap.set(actionIndex, '');\n }\n }\n\n const writeCurrentState = (): void => {\n const output = mergeReviewedSegments(\n plan,\n targetBlocks,\n reviewedSegmentsMap\n );\n mkdirSync(dirname(outputFilePath), { recursive: true });\n writeFileSync(outputFilePath, output);\n };\n\n if (deleteCount > 0) {\n writeCurrentState();\n applicationLogger(\n `${filePrefix}${colorizeNumber(deleteCount)} block(s) deleted without AI.`\n );\n }\n\n if (segmentsToReview.length === 0) {\n if (deleteCount === 0) {\n applicationLogger(\n `${filePrefix}No segments need review, reusing existing translation`\n );\n writeCurrentState();\n }\n applicationLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(outputFilePath)} updated successfully (no changes needed).`\n );\n return reviewSummary;\n }\n\n applicationLogger(\n `${filePrefix}Segments to review: ${colorizeNumber(segmentsToReview.length)} (processing bottom-up)`\n );\n\n // --- Step 2: process AI segments in bottom-up order ---\n // Reversing ensures edits near the end of the file don't shift line numbers\n // that matter for blocks higher up, and each intermediate file write is valid.\n const segmentsBottomUp = segmentsToReview\n .map((segment, originalIndex) => ({\n segment,\n displayNumber: originalIndex + 1,\n }))\n .reverse();\n\n for (const { segment, displayNumber } of segmentsBottomUp) {\n const baseBlock = segment.baseBlock;\n\n const getBaseChunkContextPrompt = () =>\n `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the base block in ${formatLocale(baseLocale, false)} as reference.\\n` +\n `///chunksStart///\\n${ \n baseBlock.content \n }///chunksEnd///`;\n\n const getTargetChunkPrompt = () =>\n `**BLOCK ${displayNumber} of ${segmentsToReview.length}** is the current block to review in ${formatLocale(locale, false)}.\\n` +\n `///chunksStart///\\n${ \n segment.targetBlockText ?? '' \n }///chunksEnd///`;\n\n const reviewedChunkResult = await retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n { role: 'system', content: getBaseChunkContextPrompt() },\n { role: 'system', content: getTargetChunkPrompt() },\n {\n role: 'system',\n content: `The next user message will be the **BLOCK ${colorizeNumber(displayNumber)} of ${colorizeNumber(segmentsToReview.length)}** that should be translated in ${getLocaleName(locale, ENGLISH)} (${locale}).`,\n },\n ],\n [{ role: 'user', content: baseBlock.content }],\n aiOptions,\n configuration,\n aiClient,\n aiConfig\n );\n\n applicationLogger(\n `${prefix}${colorizeNumber(result.tokenUsed)} tokens used - Block ${colorizeNumber(displayNumber)} of ${colorizeNumber(segmentsToReview.length)}`\n );\n\n let processedChunk = sanitizeChunk(\n result?.fileContent,\n baseBlock.content\n );\n processedChunk = fixChunkStartEndChars(processedChunk, baseBlock.content);\n\n const isValid = validateTranslation(\n baseBlock.content,\n processedChunk,\n applicationLogger\n );\n\n if (!isValid) {\n throw new Error(\n 'Validation failed for chunk (structure or length mismatch). Retrying...'\n );\n }\n\n return processedChunk;\n })();\n\n reviewedSegmentsMap.set(segment.actionIndex, reviewedChunkResult);\n\n // Rewrite the file after every block so progress is never lost.\n writeCurrentState();\n }\n\n applicationLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(outputFilePath)} created/updated successfully.`\n );\n\n return reviewSummary;\n};\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
+ import { existsSync } from "node:fs";
1
2
  import { getAppLogger } from "@intlayer/config/logger";
2
3
  import { getConfiguration } from "@intlayer/config/node";
3
- import { existsSync } from "node:fs";
4
- import { readFile } from "node:fs/promises";
5
4
  import { formatLocale, formatPath } from "@intlayer/engine/utils";
5
+ import { readFile } from "node:fs/promises";
6
6
  import { buildReviewReport, formatReviewReport } from "@intlayer/engine/docReview";
7
7
 
8
8
  // src/reviewDoc/reviewDocLog.ts
@@ -1,6 +1,6 @@
1
1
  import { getConfiguration } from "@intlayer/config/node";
2
- import { logConfigDetails } from "@intlayer/engine/cli";
3
2
  import { getUnmergedDictionaries } from "@intlayer/dictionaries-entry/unmerged";
3
+ import { logConfigDetails } from "@intlayer/engine/cli";
4
4
  import { getMissingLocalesContentFromDictionary } from "@intlayer/core/plugins";
5
5
  import { getDictionaries } from "@intlayer/dictionaries-entry";
6
6
 
@@ -2,8 +2,8 @@ import { listMissingTranslations } from "./listMissingTranslations.mjs";
2
2
  import * as ANSIColors from "@intlayer/config/colors";
3
3
  import { colon, colorize, colorizeKey, colorizeNumber, getAppLogger } from "@intlayer/config/logger";
4
4
  import { getConfiguration } from "@intlayer/config/node";
5
- import { formatLocale, formatPath } from "@intlayer/engine/utils";
6
5
  import { prepareIntlayer } from "@intlayer/engine/build";
6
+ import { formatLocale, formatPath } from "@intlayer/engine/utils";
7
7
 
8
8
  // src/test/test.ts
9
9
  const testMissingTranslations = async (options) => {
@@ -2,12 +2,12 @@ import { checkFileModifiedRange } from "../utils/checkFileModifiedRange.mjs";
2
2
  import { getOutputFilePath } from "../utils/getOutputFilePath.mjs";
3
3
  import { setupAI } from "../utils/setupAI.mjs";
4
4
  import { translateFile } from "./translateFile.mjs";
5
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
5
7
  import * as ANSIColors from "@intlayer/config/colors";
6
8
  import { colorize, colorizeNumber, getAppLogger, x } from "@intlayer/config/logger";
7
9
  import { getConfiguration } from "@intlayer/config/node";
8
10
  import { listGitFiles, logConfigDetails } from "@intlayer/engine/cli";
9
- import { dirname, join } from "node:path";
10
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
11
11
  import { pLimit, parallelize } from "@intlayer/config/utils";
12
12
  import fg from "fast-glob";
13
13
  import { performance } from "node:perf_hooks";
@@ -3,11 +3,11 @@ import { chunkText } from "../utils/calculateChunks.mjs";
3
3
  import { chunkInference } from "../utils/chunkInference.mjs";
4
4
  import { fixChunkStartEndChars } from "../utils/fixChunkStartEndChars.mjs";
5
5
  import { sanitizeChunk, validateTranslation } from "./validation.mjs";
6
+ import { dirname, relative } from "node:path";
6
7
  import * as ANSIColors from "@intlayer/config/colors";
7
8
  import { colon, colorize, colorizeNumber, getAppLogger } from "@intlayer/config/logger";
8
- import { dirname, relative } from "node:path";
9
- import { mkdir, readFile, writeFile } from "node:fs/promises";
10
9
  import { formatLocale, formatPath } from "@intlayer/engine/utils";
10
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
11
11
  import { retryManager } from "@intlayer/config/utils";
12
12
  import { performance } from "node:perf_hooks";
13
13
 
@@ -34,8 +34,8 @@ const translateFile = async ({ baseFilePath, outputFilePath, locale, baseLocale,
34
34
  const chunkStartTime = performance.now();
35
35
  const isFirstChunk = i === 0;
36
36
  const fileToTranslateCurrentChunk = chunk.content;
37
- const getPrevChunkPrompt = () => `>>> CONTEXT: PREVIOUS SOURCE CONTENT <<<\n\`\`\`\n` + (chunks[i - 1]?.content ?? "") + `\n\`\`\`\n>>> END PREVIOUS CONTEXT <<<`;
38
- const getBaseChunkContextPrompt = () => `>>> CONTEXT: NEXT CONTENT <<<\n\`\`\`\n` + (chunks[i + 1]?.content ?? "") + `\n\`\`\`\n>>> END NEXT CONTEXT <<<`;
37
+ const getPrevChunkPrompt = () => `>>> CONTEXT: PREVIOUS SOURCE CONTENT <<<\n\`\`\`\n${chunks[i - 1]?.content ?? ""}\n\`\`\`\n>>> END PREVIOUS CONTEXT <<<`;
38
+ const getBaseChunkContextPrompt = () => `>>> CONTEXT: NEXT CONTENT <<<\n\`\`\`\n${chunks[i + 1]?.content ?? ""}\n\`\`\`\n>>> END NEXT CONTEXT <<<`;
39
39
  chunkLogger("Process started");
40
40
  const { content: translatedChunk, tokens } = await retryManager(async () => {
41
41
  const result = await chunkInference([
@@ -1 +1 @@
1
- {"version":3,"file":"translateFile.mjs","names":[],"sources":["../../../src/translateDoc/translateFile.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, relative } from 'node:path';\nimport { performance } from 'node:perf_hooks';\nimport { readAsset } from 'utils:asset';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport { formatLocale, formatPath } from '@intlayer/engine/utils';\nimport { chunkText } from '../utils/calculateChunks';\nimport { chunkInference } from '../utils/chunkInference';\nimport { fixChunkStartEndChars } from '../utils/fixChunkStartEndChars';\nimport type { TranslateFileOptions } from './types';\nimport { sanitizeChunk, validateTranslation } from './validation';\n\nexport const translateFile = async ({\n baseFilePath,\n outputFilePath,\n locale,\n baseLocale,\n configuration,\n errorState,\n aiOptions,\n customInstructions,\n aiClient,\n aiConfig,\n flushStrategy = 'incremental',\n onChunkReceive,\n limit, // The Global Limiter\n}: TranslateFileOptions): Promise<string | null> => {\n if (errorState.shouldStop) return null;\n\n const appLogger = getAppLogger(configuration, { config: { prefix: '' } });\n const fileStartTime = performance.now();\n\n try {\n const fileContent = await readFile(baseFilePath, 'utf-8');\n const chunks = chunkText(fileContent);\n const totalChunks = chunks.length;\n\n const filePrefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}] `;\n const filePrefix = `${colon(filePrefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n const prefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}][${formatLocale(locale)}${ANSIColors.GREY_DARK}] `;\n const prefix = `${colon(prefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n\n appLogger(\n `${filePrefix}Split into ${colorizeNumber(totalChunks)} chunks. Queuing...`\n );\n\n const basePrompt = readAsset('./prompts/TRANSLATE_PROMPT.md', 'utf-8')\n .replaceAll('{{localeName}}', `${formatLocale(locale, false)}`)\n .replaceAll('{{baseLocaleName}}', `${formatLocale(baseLocale, false)}`)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const translatedParts: string[] = new Array(totalChunks).fill('');\n\n // Fallback if no limiter is provided (runs immediately)\n const runTask = limit ?? ((fn) => fn());\n\n // MAP CHUNKS TO GLOBAL TASKS\n // This pushes ALL chunks for this file into the Global Queue immediately.\n // They will execute whenever the global concurrency slots open up.\n const tasks = chunks.map((chunk, i) =>\n runTask(async () => {\n if (errorState.shouldStop) return null;\n\n const chunkLogger = getAppLogger(configuration, {\n config: {\n prefix: `${prefix} ${ANSIColors.GREY_DARK}[${i + 1}/${totalChunks}] ${ANSIColors.RESET}`,\n },\n });\n\n const chunkStartTime = performance.now();\n const isFirstChunk = i === 0;\n const fileToTranslateCurrentChunk = chunk.content;\n\n // Context Preparation\n const getPrevChunkPrompt = () =>\n `>>> CONTEXT: PREVIOUS SOURCE CONTENT <<<\\n\\`\\`\\`\\n` +\n (chunks[i - 1]?.content ?? '') +\n `\\n\\`\\`\\`\\n>>> END PREVIOUS CONTEXT <<<`;\n\n const getBaseChunkContextPrompt = () =>\n `>>> CONTEXT: NEXT CONTENT <<<\\n\\`\\`\\`\\n` +\n (chunks[i + 1]?.content ?? '') +\n `\\n\\`\\`\\`\\n>>> END NEXT CONTEXT <<<`;\n\n chunkLogger('Process started');\n\n const chunkTranslation = retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n ...(chunks[i + 1]\n ? [\n {\n role: 'system',\n content: getBaseChunkContextPrompt(),\n } as const,\n ]\n : []),\n ...(isFirstChunk\n ? []\n : [{ role: 'system', content: getPrevChunkPrompt() } as const]),\n {\n role: 'system',\n content: [\n `You are translating TARGET CHUNK (${i + 1}/${totalChunks}).`,\n `Translate ONLY the target chunk. Preserve frontmatter/code exactly.`,\n ].join('\\n'),\n },\n ],\n [\n {\n role: 'user',\n content: `>>> TARGET CHUNK START <<<\\n${fileToTranslateCurrentChunk}\\n>>> TARGET CHUNK END <<<`,\n },\n ],\n aiOptions,\n configuration,\n aiClient,\n aiConfig\n );\n\n let processedChunk = sanitizeChunk(\n result?.fileContent,\n fileToTranslateCurrentChunk\n );\n processedChunk = fixChunkStartEndChars(\n processedChunk,\n fileToTranslateCurrentChunk\n );\n\n const isValid = validateTranslation(\n fileToTranslateCurrentChunk,\n processedChunk,\n chunkLogger\n );\n\n if (!isValid) {\n // Throwing an error here signals retryManager to try again\n throw new Error(\n `Validation failed for chunk ${i + 1}/${totalChunks}`\n );\n }\n\n return { content: processedChunk, tokens: result.tokenUsed };\n });\n\n const { content: translatedChunk, tokens } = await chunkTranslation();\n const chunkEndTime = performance.now();\n const chunkDuration = (chunkEndTime - chunkStartTime).toFixed(0);\n\n // Store Result\n translatedParts[i] = translatedChunk;\n\n if (onChunkReceive) {\n onChunkReceive(translatedChunk, i, totalChunks);\n }\n\n // Incremental Flush Strategy\n if (flushStrategy === 'incremental') {\n const isContiguous = translatedParts\n .slice(0, i + 1)\n .every((p) => p && p !== '');\n\n if (isContiguous) {\n let endIdx = 0;\n while (\n endIdx < totalChunks &&\n translatedParts[endIdx] &&\n translatedParts[endIdx] !== ''\n ) {\n endIdx++;\n }\n const currentContent = translatedParts.slice(0, endIdx).join('');\n // Write asynchronously/sync is fine here as node handles file locks reasonably well for single process\n await mkdir(dirname(outputFilePath), { recursive: true });\n await writeFile(outputFilePath, currentContent);\n }\n }\n\n chunkLogger(\n [\n `${colorizeNumber(tokens)} tokens used `,\n `${ANSIColors.GREY_DARK}in ${colorizeNumber(chunkDuration)}ms${ANSIColors.RESET}`,\n ].join('')\n );\n })\n );\n\n // Wait for all chunks for this specific file/locale to finish\n await Promise.all(tasks);\n\n // Final Flush\n const fullContent = translatedParts.join('');\n if (flushStrategy === 'end' || flushStrategy === 'incremental') {\n await mkdir(dirname(outputFilePath), { recursive: true });\n await writeFile(outputFilePath, fullContent);\n }\n\n const fileEndTime = performance.now();\n const totalDuration = ((fileEndTime - fileStartTime) / 1000).toFixed(2);\n const relativePath = relative(configuration.system.baseDir, outputFilePath);\n\n appLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(relativePath)} completed in ${colorizeNumber(totalDuration)}s.`\n );\n\n return fullContent;\n } catch (error: any) {\n errorState.count++;\n const errorMessage = error?.message ?? JSON.stringify(error);\n appLogger(`${colorize('✖', ANSIColors.RED)} Error: ${errorMessage}`);\n if (errorState.count >= errorState.maxErrors) errorState.shouldStop = true;\n return null;\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"translateFile.mjs","names":[],"sources":["../../../src/translateDoc/translateFile.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, relative } from 'node:path';\nimport { performance } from 'node:perf_hooks';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeNumber,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport { retryManager } from '@intlayer/config/utils';\nimport { formatLocale, formatPath } from '@intlayer/engine/utils';\nimport { readAsset } from 'utils:asset';\nimport { chunkText } from '../utils/calculateChunks';\nimport { chunkInference } from '../utils/chunkInference';\nimport { fixChunkStartEndChars } from '../utils/fixChunkStartEndChars';\nimport type { TranslateFileOptions } from './types';\nimport { sanitizeChunk, validateTranslation } from './validation';\n\nexport const translateFile = async ({\n baseFilePath,\n outputFilePath,\n locale,\n baseLocale,\n configuration,\n errorState,\n aiOptions,\n customInstructions,\n aiClient,\n aiConfig,\n flushStrategy = 'incremental',\n onChunkReceive,\n limit, // The Global Limiter\n}: TranslateFileOptions): Promise<string | null> => {\n if (errorState.shouldStop) return null;\n\n const appLogger = getAppLogger(configuration, { config: { prefix: '' } });\n const fileStartTime = performance.now();\n\n try {\n const fileContent = await readFile(baseFilePath, 'utf-8');\n const chunks = chunkText(fileContent);\n const totalChunks = chunks.length;\n\n const filePrefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}] `;\n const filePrefix = `${colon(filePrefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n const prefixText = `${ANSIColors.GREY_DARK}[${formatPath(baseFilePath)}${ANSIColors.GREY_DARK}][${formatLocale(locale)}${ANSIColors.GREY_DARK}] `;\n const prefix = `${colon(prefixText, { colSize: 40 })}${ANSIColors.RESET}`;\n\n appLogger(\n `${filePrefix}Split into ${colorizeNumber(totalChunks)} chunks. Queuing...`\n );\n\n const basePrompt = readAsset('./prompts/TRANSLATE_PROMPT.md', 'utf-8')\n .replaceAll('{{localeName}}', `${formatLocale(locale, false)}`)\n .replaceAll('{{baseLocaleName}}', `${formatLocale(baseLocale, false)}`)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '-')\n .replace('{{customInstructions}}', customInstructions ?? '-');\n\n const translatedParts: string[] = new Array(totalChunks).fill('');\n\n // Fallback if no limiter is provided (runs immediately)\n const runTask = limit ?? ((fn) => fn());\n\n // MAP CHUNKS TO GLOBAL TASKS\n // This pushes ALL chunks for this file into the Global Queue immediately.\n // They will execute whenever the global concurrency slots open up.\n const tasks = chunks.map((chunk, i) =>\n runTask(async () => {\n if (errorState.shouldStop) return null;\n\n const chunkLogger = getAppLogger(configuration, {\n config: {\n prefix: `${prefix} ${ANSIColors.GREY_DARK}[${i + 1}/${totalChunks}] ${ANSIColors.RESET}`,\n },\n });\n\n const chunkStartTime = performance.now();\n const isFirstChunk = i === 0;\n const fileToTranslateCurrentChunk = chunk.content;\n\n // Context Preparation\n const getPrevChunkPrompt = () =>\n `>>> CONTEXT: PREVIOUS SOURCE CONTENT <<<\\n\\`\\`\\`\\n${ \n chunks[i - 1]?.content ?? '' \n }\\n\\`\\`\\`\\n>>> END PREVIOUS CONTEXT <<<`;\n\n const getBaseChunkContextPrompt = () =>\n `>>> CONTEXT: NEXT CONTENT <<<\\n\\`\\`\\`\\n${ \n chunks[i + 1]?.content ?? '' \n }\\n\\`\\`\\`\\n>>> END NEXT CONTEXT <<<`;\n\n chunkLogger('Process started');\n\n const chunkTranslation = retryManager(async () => {\n const result = await chunkInference(\n [\n { role: 'system', content: basePrompt },\n ...(chunks[i + 1]\n ? [\n {\n role: 'system',\n content: getBaseChunkContextPrompt(),\n } as const,\n ]\n : []),\n ...(isFirstChunk\n ? []\n : [{ role: 'system', content: getPrevChunkPrompt() } as const]),\n {\n role: 'system',\n content: [\n `You are translating TARGET CHUNK (${i + 1}/${totalChunks}).`,\n `Translate ONLY the target chunk. Preserve frontmatter/code exactly.`,\n ].join('\\n'),\n },\n ],\n [\n {\n role: 'user',\n content: `>>> TARGET CHUNK START <<<\\n${fileToTranslateCurrentChunk}\\n>>> TARGET CHUNK END <<<`,\n },\n ],\n aiOptions,\n configuration,\n aiClient,\n aiConfig\n );\n\n let processedChunk = sanitizeChunk(\n result?.fileContent,\n fileToTranslateCurrentChunk\n );\n processedChunk = fixChunkStartEndChars(\n processedChunk,\n fileToTranslateCurrentChunk\n );\n\n const isValid = validateTranslation(\n fileToTranslateCurrentChunk,\n processedChunk,\n chunkLogger\n );\n\n if (!isValid) {\n // Throwing an error here signals retryManager to try again\n throw new Error(\n `Validation failed for chunk ${i + 1}/${totalChunks}`\n );\n }\n\n return { content: processedChunk, tokens: result.tokenUsed };\n });\n\n const { content: translatedChunk, tokens } = await chunkTranslation();\n const chunkEndTime = performance.now();\n const chunkDuration = (chunkEndTime - chunkStartTime).toFixed(0);\n\n // Store Result\n translatedParts[i] = translatedChunk;\n\n if (onChunkReceive) {\n onChunkReceive(translatedChunk, i, totalChunks);\n }\n\n // Incremental Flush Strategy\n if (flushStrategy === 'incremental') {\n const isContiguous = translatedParts\n .slice(0, i + 1)\n .every((p) => p && p !== '');\n\n if (isContiguous) {\n let endIdx = 0;\n while (\n endIdx < totalChunks &&\n translatedParts[endIdx] &&\n translatedParts[endIdx] !== ''\n ) {\n endIdx++;\n }\n const currentContent = translatedParts.slice(0, endIdx).join('');\n // Write asynchronously/sync is fine here as node handles file locks reasonably well for single process\n await mkdir(dirname(outputFilePath), { recursive: true });\n await writeFile(outputFilePath, currentContent);\n }\n }\n\n chunkLogger(\n [\n `${colorizeNumber(tokens)} tokens used `,\n `${ANSIColors.GREY_DARK}in ${colorizeNumber(chunkDuration)}ms${ANSIColors.RESET}`,\n ].join('')\n );\n })\n );\n\n // Wait for all chunks for this specific file/locale to finish\n await Promise.all(tasks);\n\n // Final Flush\n const fullContent = translatedParts.join('');\n if (flushStrategy === 'end' || flushStrategy === 'incremental') {\n await mkdir(dirname(outputFilePath), { recursive: true });\n await writeFile(outputFilePath, fullContent);\n }\n\n const fileEndTime = performance.now();\n const totalDuration = ((fileEndTime - fileStartTime) / 1000).toFixed(2);\n const relativePath = relative(configuration.system.baseDir, outputFilePath);\n\n appLogger(\n `${colorize('✔', ANSIColors.GREEN)} File ${formatPath(relativePath)} completed in ${colorizeNumber(totalDuration)}s.`\n );\n\n return fullContent;\n } catch (error: any) {\n errorState.count++;\n const errorMessage = error?.message ?? JSON.stringify(error);\n appLogger(`${colorize('✖', ANSIColors.RED)} Error: ${errorMessage}`);\n if (errorState.count >= errorState.maxErrors) errorState.shouldStop = true;\n return null;\n }\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { findProjectRoot } from "./init.mjs";
2
- import { upgradeIntlayerPackages } from "@intlayer/engine/cli";
3
2
  import { resolve } from "node:path";
3
+ import { upgradeIntlayerPackages } from "@intlayer/engine/cli";
4
4
 
5
5
  // src/upgrade.ts
6
6
  /**
@@ -3,8 +3,8 @@ import { readCliSessionToken } from "../auth/sessionToken.mjs";
3
3
  import { checkConfigConsistency } from "./checkConfigConsistency.mjs";
4
4
  import * as ANSIColors from "@intlayer/config/colors";
5
5
  import { colorize, getAppLogger } from "@intlayer/config/logger";
6
- import { extractErrorMessage } from "@intlayer/config/utils";
7
6
  import { getIntlayerAPIProxy } from "@intlayer/api";
7
+ import { extractErrorMessage } from "@intlayer/config/utils";
8
8
 
9
9
  // src/utils/checkAccess.ts
10
10
  const getAuthenticatedAPI = async (configuration) => {
@@ -1,5 +1,5 @@
1
- import { searchConfigurationFile } from "@intlayer/config/node";
2
1
  import { relative, sep } from "node:path";
2
+ import { searchConfigurationFile } from "@intlayer/config/node";
3
3
  import { spawnSync } from "node:child_process";
4
4
 
5
5
  // src/utils/detectGitRepository.ts
@@ -1,5 +1,5 @@
1
- import { dirname, resolve } from "node:path";
2
1
  import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
3
 
4
4
  // src/utils/getParentPackageJSON.ts
5
5
  const getParentPackageJSON = (startDir) => {
@@ -1,5 +1,5 @@
1
- import { DictionaryAPI } from "@intlayer/api";
2
1
  import { IntlayerConfig } from "@intlayer/types/config";
2
+ import { DictionaryAPI } from "@intlayer/api";
3
3
  export type IntlayerMessageEvent = MessageEvent;
4
4
  /**
5
5
  * IntlayerEventListener class to listen for dictionary changes via SSE (Server-Sent Events).
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","names":[],"sources":["../../src/bundle.ts"],"mappings":";qBA8Ca,SAAM,SAAmB,0BAAwB"}
1
+ {"version":3,"file":"bundle.d.ts","names":[],"sources":["../../src/bundle.ts"],"mappings":";qBA6Ca,SAAM,SAAmB,0BAAwB"}
@@ -1,6 +1,6 @@
1
1
  import { GetTargetDictionaryOptions } from "../getTargetDictionary.js";
2
- import { AIOptions } from "@intlayer/ai";
3
2
  import { ListGitFilesOptions } from "@intlayer/engine/cli";
3
+ import { AIOptions } from "@intlayer/ai";
4
4
  import { Locale } from "@intlayer/types/allLocales";
5
5
  export type FillOptions = {
6
6
  sourceLocale?: Locale;
@@ -1,5 +1,5 @@
1
- import { IntlayerConfig } from "@intlayer/types/config";
2
1
  import { FilePathPattern } from "@intlayer/types/filePathPattern";
2
+ import { IntlayerConfig } from "@intlayer/types/config";
3
3
  import { Locale } from "@intlayer/types/allLocales";
4
4
  export declare const formatAutoFilledFilePath: (autoFillField: FilePathPattern, dictionaryKey: string, dictionaryFilePath: string, baseDir: string, configuration: IntlayerConfig, locale?: Locale) => Promise<string>;
5
5
  //# sourceMappingURL=formatAutoFilledFilePath.d.ts.map
@@ -7,14 +7,14 @@ import { getRemoteEditorRunners, startEditor } from "./editor.js";
7
7
  import { extract } from "./extract.js";
8
8
  import { FillOptions, FillResult, fill } from "./fill/fill.js";
9
9
  import { IntlayerEventListener, IntlayerMessageEvent } from "./IntlayerEventListener.js";
10
- import { CONTENT_LAYOUT_CHOICES, DEFAULT_INIT_STEPS, ESLINT_CONFIG_FILES, INIT_STEP_COMMANDS, INIT_STEP_GROUPS, InitStep, InitStepOption, LOCALE_ROUTING_CHOICES, LocaleRoutingChoice, OPT_IN_INIT_STEPS, findProjectRoot, getContentInitOptions, getInitOptionsForSteps, getInitialInitSteps, getProjectDependencies, getRoutingInitOptions, init, initCms, initRepository, initSteps, isEslintInstalled, parseContentLayoutChoice, parseLocaleRoutingChoice, resolveProjectRoot } from "./init.js";
10
+ import { CONTENT_LAYOUT_CHOICES, DEFAULT_INIT_STEPS, ESLINT_CONFIG_FILES, INIT_STEP_COMMANDS, INIT_STEP_GROUPS, InitStep, InitStepOption, LOCALE_ROUTING_CHOICES, LocaleRoutingChoice, OPT_IN_INIT_STEPS, findProjectRoot, getContentInitOptions, getInitOptionsForSteps, getInitialInitSteps, getProjectDependencies, getRoutingInitOptions, init, initCms, initRepository, initSteps, isEslintInstalled, isPrettierInstalled, parseContentLayoutChoice, parseLocaleRoutingChoice, resolveProjectRoot } from "./init.js";
11
11
  import { BROWSER_EXTENSION_OPTIONS, CHROME_EXTENSION_URL, EXTENSION_BROWSERS, EXTENSION_URL_BY_BROWSER, ExtensionBrowser, InitChromeExtensionOptions, MOZILLA_EXTENSION_URL, initChromeExtension, parseExtensionBrowsers } from "./initChromeExtension.js";
12
12
  import { INFRA_MODES, INSTALL_SCRIPT_URL, INSTALL_SCRIPT_URL_WINDOWS, InfraMode, InitInfraOptions, initInfra, parseInfraMode } from "./initInfra.js";
13
13
  import { InitSkillsOptions, PLATFORM_OPTIONS, initSkills, parsePlatform, parseSkills, promptPlatform, resolvePlatformWithoutPrompt } from "./initSkills.js";
14
14
  import { listContentDeclaration, listContentDeclarationRows } from "./listContentDeclaration.js";
15
15
  import { ListProjectsCommandOptions, listProjectsCommand } from "./listProjects.js";
16
16
  import { liveSync } from "./liveSync.js";
17
- import { pull } from "./pull.js";
17
+ import { PulledDictionary, pull } from "./pull.js";
18
18
  import { push } from "./push/push.js";
19
19
  import { pushConfig } from "./pushConfig.js";
20
20
  import { ReviewDocMode, reviewDoc } from "./reviewDoc/reviewDoc.js";
@@ -30,4 +30,4 @@ export type * from "@intlayer/engine/cli";
30
30
  export type * from "@intlayer/engine/build";
31
31
  export type * from "@intlayer/engine/utils";
32
32
  export type * from "@intlayer/engine/watcher";
33
- export { BROWSER_EXTENSION_OPTIONS, CHROME_EXTENSION_URL, CONTENT_LAYOUT_CHOICES, ConfigurationOptions, DEFAULT_INIT_STEPS, ESLINT_CONFIG_FILES, EXTENSION_BROWSERS, EXTENSION_URL_BY_BROWSER, ExtensionBrowser, FillOptions, FillResult, INFRA_MODES, INIT_STEP_COMMANDS, INIT_STEP_GROUPS, INSTALL_SCRIPT_URL, INSTALL_SCRIPT_URL_WINDOWS, InfraMode, InitChromeExtensionOptions, InitInfraOptions, InitSkillsOptions, InitStep, InitStepOption, IntlayerEventListener, IntlayerMessageEvent, LOCALE_ROUTING_CHOICES, ListProjectsCommandOptions, LocaleRoutingChoice, MOZILLA_EXTENSION_URL, OPT_IN_INIT_STEPS, PLATFORM_OPTIONS, ReviewDocMode, ScanCommandOptions, build, bundle, checkCMSAuth, checkConfigConsistency, clearCliSessionToken, dirname, extract, fill, findProjectRoot, getAuthenticatedAPI, getContentInitOptions, getInitOptionsForSteps, getInitialInitSteps, getProjectDependencies, getRemoteEditorRunners, getRoutingInitOptions, init, initChromeExtension, initCms, initInfra, initRepository, initSkills, initSteps, isEslintInstalled, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, listProjectsCommand, liveSync, login, parseContentLayoutChoice, parseExtensionBrowsers, parseInfraMode, parseLocaleRoutingChoice, parsePlatform, parseSkills, promptPlatform, pull, push, pushConfig, readCliSessionToken, resolvePlatformWithoutPrompt, resolveProjectRoot, reviewDoc, scan, searchDoc, setAPI, startEditor, testMissingTranslations, translateDoc };
33
+ export { BROWSER_EXTENSION_OPTIONS, CHROME_EXTENSION_URL, CONTENT_LAYOUT_CHOICES, ConfigurationOptions, DEFAULT_INIT_STEPS, ESLINT_CONFIG_FILES, EXTENSION_BROWSERS, EXTENSION_URL_BY_BROWSER, ExtensionBrowser, FillOptions, FillResult, INFRA_MODES, INIT_STEP_COMMANDS, INIT_STEP_GROUPS, INSTALL_SCRIPT_URL, INSTALL_SCRIPT_URL_WINDOWS, InfraMode, InitChromeExtensionOptions, InitInfraOptions, InitSkillsOptions, InitStep, InitStepOption, IntlayerEventListener, IntlayerMessageEvent, LOCALE_ROUTING_CHOICES, ListProjectsCommandOptions, LocaleRoutingChoice, MOZILLA_EXTENSION_URL, OPT_IN_INIT_STEPS, PLATFORM_OPTIONS, PulledDictionary, ReviewDocMode, ScanCommandOptions, build, bundle, checkCMSAuth, checkConfigConsistency, clearCliSessionToken, dirname, extract, fill, findProjectRoot, getAuthenticatedAPI, getContentInitOptions, getInitOptionsForSteps, getInitialInitSteps, getProjectDependencies, getRemoteEditorRunners, getRoutingInitOptions, init, initChromeExtension, initCms, initInfra, initRepository, initSkills, initSteps, isEslintInstalled, isPrettierInstalled, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, listProjectsCommand, liveSync, login, parseContentLayoutChoice, parseExtensionBrowsers, parseInfraMode, parseLocaleRoutingChoice, parsePlatform, parseSkills, promptPlatform, pull, push, pushConfig, readCliSessionToken, resolvePlatformWithoutPrompt, resolveProjectRoot, reviewDoc, scan, searchDoc, setAPI, startEditor, testMissingTranslations, translateDoc };
@@ -3,7 +3,7 @@ export declare const findProjectRoot: (startDir: string) => string;
3
3
  /** Resolves the project root from `--project-root`, else the working directory. */
4
4
  export declare const resolveProjectRoot: (projectRoot?: string) => string;
5
5
  /** Individually selectable setup steps exposed by the interactive init flow. */
6
- export type InitStep = 'packages' | 'githubActions' | 'projectSetup' | 'vscodeExtension' | 'lsp' | 'eslint' | 'skills' | 'mcp' | 'infra' | 'cms' | 'repository' | 'chromeExtension';
6
+ export type InitStep = 'packages' | 'githubActions' | 'projectSetup' | 'vscodeExtension' | 'lsp' | 'eslint' | 'prettier' | 'skills' | 'mcp' | 'infra' | 'cms' | 'repository' | 'chromeExtension';
7
7
  /** A checkbox entry of the interactive init flow. */
8
8
  export type InitStepOption = {
9
9
  value: InitStep;
@@ -82,6 +82,10 @@ export declare const ESLINT_CONFIG_FILES: string[];
82
82
  * configured in the project.
83
83
  */
84
84
  export declare const isEslintInstalled: (dependencies: Record<string, string>, root?: string) => boolean;
85
+ /**
86
+ * Checks whether Prettier is installed or configured in the project.
87
+ */
88
+ export declare const isPrettierInstalled: (dependencies: Record<string, string>, root?: string) => boolean;
85
89
  /**
86
90
  * Computes the initial setup steps selected by default in the interactive prompt.
87
91
  * Steps like infrastructure and browser extension require opt-in, while
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","names":[],"sources":["../../src/init.ts"],"mappings":";qBA4Ba,kBAAe;;qBAgBf,qBAAkB;;YAInB;;YAeA;EACV,OAAO;EACP;EACA;;;;;;;qBAQW,mBAAmB;;;;;;;qBAQnB,oBAAoB;;;;;qBAMpB,oBAAoB,OAAO;;;;;;qBAqB3B,yBAAsB,OAC1B,YAAU,cACH,gBACb;;;;;;qBAwBU,YAAS,iCACW,OACxB,YAAU,UACP,gBACT;;;;;qBAWU,UAAO,yBAAiC;;;;;qBAiBxC,iBAAc,yBAAiC;;qBAyB/C,kBAAkB,eAAe;;;;;YA2ElC,sBAAsB;;qBAoCrB,wBAAsB;;qBAKtB,2BAAwB,kBAAoB;;qBAI5C,wBAAqB,QACxB,wBACP,KAAK;;qBAoDK,wBAAsB;;qBAKtB,2BAAwB,kBAAoB;;KAIpD,qBAAqB,KACxB;;;;;;qBAaW,wBAAqB,sBACZ,sBACA,gCAEnB;;qBAwCU;;;;;qBAoBA,oBAAiB,cACd,wBAAsB;;;;;;qBAkBzB,sBAAmB,cAChB,wBAAsB,kBAEnC;;qBAcU,yBAAsB,iBAEhC;;;;;;qBA0MU,OAAI,sBACK,UACV,aAAW,0BACA"}
1
+ {"version":3,"file":"init.d.ts","names":[],"sources":["../../src/init.ts"],"mappings":";qBA8Ba,kBAAe;;qBAgBf,qBAAkB;;YAInB;;YAgBA;EACV,OAAO;EACP;EACA;;;;;;;qBAQW,mBAAmB;;;;;;;qBAQnB,oBAAoB;;;;;qBAMpB,oBAAoB,OAAO;;;;;;qBAsB3B,yBAAsB,OAC1B,YAAU,cACH,gBACb;;;;;;qBAyBU,YAAS,iCACW,OACxB,YAAU,UACP,gBACT;;;;;qBAWU,UAAO,yBAAiC;;;;;qBAiBxC,iBAAc,yBAAiC;;qBAyB/C,kBAAkB,eAAe;;;;;YAgFlC,sBAAsB;;qBAoCrB,wBAAsB;;qBAKtB,2BAAwB,kBAAoB;;qBAI5C,wBAAqB,QACxB,wBACP,KAAK;;qBAoDK,wBAAsB;;qBAKtB,2BAAwB,kBAAoB;;KAIpD,qBAAqB,KACxB;;;;;;qBAaW,wBAAqB,sBACZ,sBACA,gCAEnB;;qBAwCU;;;;;qBAoBA,oBAAiB,cACd,wBAAsB;;;;qBAgBzB,sBAAmB,cAChB,wBAAsB;;;;;;qBAiBzB,sBAAmB,cAChB,wBAAsB,kBAEnC;;qBAgBU,yBAAsB,iBAEhC;;;;;;qBA0MU,OAAI,sBACK,UACV,aAAW,0BACA"}
@@ -1,13 +1,26 @@
1
1
  import { GetConfigurationOptions } from "@intlayer/config/node";
2
+ import { DictionaryStatus } from "@intlayer/engine/build";
2
3
  type PullOptions = {
3
4
  dictionaries?: string[];
4
5
  newDictionariesPath?: string;
5
6
  configOptions?: GetConfigurationOptions;
6
7
  };
8
+ type DictionariesStatus = {
9
+ dictionaryKey: string;
10
+ status: DictionaryStatus | 'pending' | 'fetching' | 'error';
11
+ error?: Error;
12
+ errorMessage?: string;
13
+ /** Content declaration file written for the dictionary */
14
+ filePath?: string;
15
+ };
16
+ /** Outcome of one dictionary of a pull. */
17
+ export type PulledDictionary = Pick<DictionariesStatus, 'dictionaryKey' | 'status' | 'filePath'>;
7
18
  /**
8
19
  * Fetch distant dictionaries and write them locally,
9
20
  * with progress indicators and concurrency control.
21
+ *
22
+ * @returns The outcome of each pulled dictionary (empty when nothing ran).
10
23
  */
11
- export declare const pull: (options?: PullOptions) => Promise<void>;
24
+ export declare const pull: (options?: PullOptions) => Promise<PulledDictionary[]>;
12
25
  export {};
13
26
  //# sourceMappingURL=pull.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","names":[],"sources":["../../src/pull.ts"],"mappings":";KAoBK;EACH;EACA;EACA,gBAAgB;;;;;;qBAcL,OAAI,UAAoB,gBAAc"}
1
+ {"version":3,"file":"pull.d.ts","names":[],"sources":["../../src/pull.ts"],"mappings":";;KAoBK;EACH;EACA;EACA,gBAAgB;;KAGb;EACH;EACA,QAAQ;EACR,QAAQ;EACR;;EAEA;;;YAIU,mBAAmB,KAC7B;;;;;;;qBAUW,OAAI,UACL,gBACT,QAAQ"}
@@ -1,7 +1,7 @@
1
1
  import { ReviewFileResult } from "./reviewDocSynthesis.js";
2
2
  import { GetConfigurationOptions } from "@intlayer/config/node";
3
- import { AIOptions } from "@intlayer/ai";
4
3
  import { ListGitFilesOptions } from "@intlayer/engine/cli";
4
+ import { AIOptions } from "@intlayer/ai";
5
5
  import { Locale } from "@intlayer/types/allLocales";
6
6
  /**
7
7
  * How the review should be run.
@@ -1,5 +1,5 @@
1
- import { IntlayerConfig } from "@intlayer/types/config";
2
1
  import { GetConfigurationOptions } from "@intlayer/config/node";
2
+ import { IntlayerConfig } from "@intlayer/types/config";
3
3
  import { Locale } from "@intlayer/types/allLocales";
4
4
  export declare const listMissingTranslationsWithConfig: (configuration: IntlayerConfig) => {
5
5
  missingTranslations: {
@@ -1,8 +1,8 @@
1
1
  import { AIClient } from "../utils/setupAI.js";
2
- import { IntlayerConfig } from "@intlayer/types/config";
3
2
  import { GetConfigurationOptions } from "@intlayer/config/node";
4
- import { AIConfig, AIOptions } from "@intlayer/ai";
5
3
  import { ListGitFilesOptions } from "@intlayer/engine/cli";
4
+ import { IntlayerConfig } from "@intlayer/types/config";
5
+ import { AIConfig, AIOptions } from "@intlayer/ai";
6
6
  import { Locale } from "@intlayer/types/allLocales";
7
7
  export type ErrorState = {
8
8
  count: number;
@@ -1,6 +1,6 @@
1
- import { IntlayerAPIProxy } from "@intlayer/api";
2
1
  import { IntlayerConfig } from "@intlayer/types/config";
3
2
  import { AIOptions } from "@intlayer/ai";
3
+ import { IntlayerAPIProxy } from "@intlayer/api";
4
4
  export declare const getAuthenticatedAPI: (configuration?: IntlayerConfig) => Promise<IntlayerAPIProxy>;
5
5
  export declare const checkCMSAuth: (configuration: IntlayerConfig, shouldCheckConfigConsistency?: boolean, shouldAutoLogin?: boolean) => Promise<boolean>;
6
6
  export declare const checkAIAccess: (configuration: IntlayerConfig, aiOptions?: AIOptions, shouldCheckConfigConsistency?: boolean) => Promise<boolean>;
@@ -1,5 +1,5 @@
1
- import { IntlayerAPIProxy } from "@intlayer/api";
2
1
  import { IntlayerConfig } from "@intlayer/types/config";
2
+ import { IntlayerAPIProxy } from "@intlayer/api";
3
3
  /**
4
4
  * Selects the CMS project environment that matches `environmentName`.
5
5
  *