@intlayer/cli 9.0.0-canary.0 → 9.0.0-canary.1

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 (90) hide show
  1. package/dist/cjs/cli.cjs +7 -3
  2. package/dist/cjs/cli.cjs.map +1 -1
  3. package/dist/cjs/reviewDoc/reviewDoc.cjs +38 -11
  4. package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
  5. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +54 -37
  6. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
  7. package/dist/cjs/reviewDoc/reviewDocLog.cjs +48 -0
  8. package/dist/cjs/reviewDoc/reviewDocLog.cjs.map +1 -0
  9. package/dist/cjs/utils/formatLineRanges.cjs +44 -0
  10. package/dist/cjs/utils/formatLineRanges.cjs.map +1 -0
  11. package/dist/esm/cli.mjs +7 -3
  12. package/dist/esm/cli.mjs.map +1 -1
  13. package/dist/esm/reviewDoc/reviewDoc.mjs +38 -11
  14. package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
  15. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +54 -37
  16. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
  17. package/dist/esm/reviewDoc/reviewDocLog.mjs +46 -0
  18. package/dist/esm/reviewDoc/reviewDocLog.mjs.map +1 -0
  19. package/dist/esm/utils/formatLineRanges.mjs +42 -0
  20. package/dist/esm/utils/formatLineRanges.mjs.map +1 -0
  21. package/dist/types/reviewDoc/reviewDoc.d.ts +8 -1
  22. package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -1
  23. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts +8 -6
  24. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -1
  25. package/dist/types/reviewDoc/reviewDocLog.d.ts +25 -0
  26. package/dist/types/reviewDoc/reviewDocLog.d.ts.map +1 -0
  27. package/dist/types/utils/formatLineRanges.d.ts +21 -0
  28. package/dist/types/utils/formatLineRanges.d.ts.map +1 -0
  29. package/package.json +13 -13
  30. package/dist/cjs/translation-alignment/alignBlocks.cjs +0 -68
  31. package/dist/cjs/translation-alignment/alignBlocks.cjs.map +0 -1
  32. package/dist/cjs/translation-alignment/computeSimilarity.cjs +0 -26
  33. package/dist/cjs/translation-alignment/computeSimilarity.cjs.map +0 -1
  34. package/dist/cjs/translation-alignment/fingerprintBlock.cjs +0 -24
  35. package/dist/cjs/translation-alignment/fingerprintBlock.cjs.map +0 -1
  36. package/dist/cjs/translation-alignment/index.cjs +0 -22
  37. package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs +0 -19
  38. package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs.map +0 -1
  39. package/dist/cjs/translation-alignment/normalizeBlock.cjs +0 -23
  40. package/dist/cjs/translation-alignment/normalizeBlock.cjs.map +0 -1
  41. package/dist/cjs/translation-alignment/pipeline.cjs +0 -38
  42. package/dist/cjs/translation-alignment/pipeline.cjs.map +0 -1
  43. package/dist/cjs/translation-alignment/planActions.cjs +0 -47
  44. package/dist/cjs/translation-alignment/planActions.cjs.map +0 -1
  45. package/dist/cjs/translation-alignment/rebuildDocument.cjs +0 -50
  46. package/dist/cjs/translation-alignment/rebuildDocument.cjs.map +0 -1
  47. package/dist/cjs/translation-alignment/segmentDocument.cjs +0 -67
  48. package/dist/cjs/translation-alignment/segmentDocument.cjs.map +0 -1
  49. package/dist/cjs/translation-alignment/types.cjs +0 -0
  50. package/dist/esm/translation-alignment/alignBlocks.mjs +0 -67
  51. package/dist/esm/translation-alignment/alignBlocks.mjs.map +0 -1
  52. package/dist/esm/translation-alignment/computeSimilarity.mjs +0 -23
  53. package/dist/esm/translation-alignment/computeSimilarity.mjs.map +0 -1
  54. package/dist/esm/translation-alignment/fingerprintBlock.mjs +0 -21
  55. package/dist/esm/translation-alignment/fingerprintBlock.mjs.map +0 -1
  56. package/dist/esm/translation-alignment/index.mjs +0 -11
  57. package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs +0 -17
  58. package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs.map +0 -1
  59. package/dist/esm/translation-alignment/normalizeBlock.mjs +0 -21
  60. package/dist/esm/translation-alignment/normalizeBlock.mjs.map +0 -1
  61. package/dist/esm/translation-alignment/pipeline.mjs +0 -36
  62. package/dist/esm/translation-alignment/pipeline.mjs.map +0 -1
  63. package/dist/esm/translation-alignment/planActions.mjs +0 -45
  64. package/dist/esm/translation-alignment/planActions.mjs.map +0 -1
  65. package/dist/esm/translation-alignment/rebuildDocument.mjs +0 -47
  66. package/dist/esm/translation-alignment/rebuildDocument.mjs.map +0 -1
  67. package/dist/esm/translation-alignment/segmentDocument.mjs +0 -65
  68. package/dist/esm/translation-alignment/segmentDocument.mjs.map +0 -1
  69. package/dist/esm/translation-alignment/types.mjs +0 -0
  70. package/dist/types/translation-alignment/alignBlocks.d.ts +0 -7
  71. package/dist/types/translation-alignment/alignBlocks.d.ts.map +0 -1
  72. package/dist/types/translation-alignment/computeSimilarity.d.ts +0 -6
  73. package/dist/types/translation-alignment/computeSimilarity.d.ts.map +0 -1
  74. package/dist/types/translation-alignment/fingerprintBlock.d.ts +0 -7
  75. package/dist/types/translation-alignment/fingerprintBlock.d.ts.map +0 -1
  76. package/dist/types/translation-alignment/index.d.ts +0 -11
  77. package/dist/types/translation-alignment/mapChangedLinesToBlocks.d.ts +0 -7
  78. package/dist/types/translation-alignment/mapChangedLinesToBlocks.d.ts.map +0 -1
  79. package/dist/types/translation-alignment/normalizeBlock.d.ts +0 -7
  80. package/dist/types/translation-alignment/normalizeBlock.d.ts.map +0 -1
  81. package/dist/types/translation-alignment/pipeline.d.ts +0 -25
  82. package/dist/types/translation-alignment/pipeline.d.ts.map +0 -1
  83. package/dist/types/translation-alignment/planActions.d.ts +0 -7
  84. package/dist/types/translation-alignment/planActions.d.ts.map +0 -1
  85. package/dist/types/translation-alignment/rebuildDocument.d.ts +0 -32
  86. package/dist/types/translation-alignment/rebuildDocument.d.ts.map +0 -1
  87. package/dist/types/translation-alignment/segmentDocument.d.ts +0 -7
  88. package/dist/types/translation-alignment/segmentDocument.d.ts.map +0 -1
  89. package/dist/types/translation-alignment/types.d.ts +0 -49
  90. package/dist/types/translation-alignment/types.d.ts.map +0 -1
@@ -0,0 +1,48 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ let node_fs = require("node:fs");
4
+ let _intlayer_chokidar_utils = require("@intlayer/chokidar/utils");
5
+ let _intlayer_config_logger = require("@intlayer/config/logger");
6
+ let _intlayer_config_node = require("@intlayer/config/node");
7
+ let node_fs_promises = require("node:fs/promises");
8
+ let _intlayer_chokidar_docReview = require("@intlayer/chokidar/docReview");
9
+
10
+ //#region src/reviewDoc/reviewDocLog.ts
11
+ /**
12
+ * Log-only review of a single file/locale pair.
13
+ *
14
+ * Instead of calling an AI to translate the changed blocks, this compares the
15
+ * base document with its translation and logs the blocks that need attention
16
+ * (with their line ranges and content) so another agent or a human can generate
17
+ * the missing translations.
18
+ *
19
+ * @param baseFilePath - Absolute path of the base (source) document.
20
+ * @param outputFilePath - Absolute path of the target (translated) document.
21
+ * @param locale - The target locale being reviewed.
22
+ * @param baseLocale - The base locale used as reference.
23
+ * @param configOptions - Optional Intlayer configuration overrides.
24
+ * @param changedLines - 1-based base line numbers that changed (from git), if any.
25
+ * @returns The structured review report.
26
+ */
27
+ const logReviewFileBlocks = async (baseFilePath, outputFilePath, locale, baseLocale, configOptions, changedLines) => {
28
+ const appLogger = (0, _intlayer_config_logger.getAppLogger)({ log: {
29
+ ...(0, _intlayer_config_node.getConfiguration)(configOptions).log,
30
+ prefix: ""
31
+ } });
32
+ const report = (0, _intlayer_chokidar_docReview.buildReviewReport)({
33
+ baseText: await (0, node_fs_promises.readFile)(baseFilePath, "utf-8"),
34
+ targetText: (0, node_fs.existsSync)(outputFilePath) ? await (0, node_fs_promises.readFile)(outputFilePath, "utf-8").catch(() => "") : "",
35
+ changedLines
36
+ });
37
+ const formatted = (0, _intlayer_chokidar_docReview.formatReviewReport)(report, {
38
+ baseLabel: (0, _intlayer_chokidar_utils.formatLocale)(baseLocale),
39
+ targetLabel: (0, _intlayer_chokidar_utils.formatLocale)(locale)
40
+ });
41
+ appLogger(`${(0, _intlayer_chokidar_utils.formatPath)(baseFilePath)} → ${(0, _intlayer_chokidar_utils.formatLocale)(locale)}`);
42
+ for (const line of formatted.split("\n")) appLogger(line);
43
+ return report;
44
+ };
45
+
46
+ //#endregion
47
+ exports.logReviewFileBlocks = logReviewFileBlocks;
48
+ //# sourceMappingURL=reviewDocLog.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewDocLog.cjs","names":[],"sources":["../../../src/reviewDoc/reviewDocLog.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport {\n buildReviewReport,\n formatReviewReport,\n type ReviewReport,\n} from '@intlayer/chokidar/docReview';\nimport { formatLocale, formatPath } from '@intlayer/chokidar/utils';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { Locale } from '@intlayer/types/allLocales';\n\n/**\n * Log-only review of a single file/locale pair.\n *\n * Instead of calling an AI to translate the changed blocks, this compares the\n * base document with its translation and logs the blocks that need attention\n * (with their line ranges and content) so another agent or a human can generate\n * the missing translations.\n *\n * @param baseFilePath - Absolute path of the base (source) document.\n * @param outputFilePath - Absolute path of the target (translated) document.\n * @param locale - The target locale being reviewed.\n * @param baseLocale - The base locale used as reference.\n * @param configOptions - Optional Intlayer configuration overrides.\n * @param changedLines - 1-based base line numbers that changed (from git), if any.\n * @returns The structured review report.\n */\nexport const logReviewFileBlocks = async (\n baseFilePath: string,\n outputFilePath: string,\n locale: Locale,\n baseLocale: Locale,\n configOptions?: GetConfigurationOptions,\n changedLines?: number[]\n): Promise<ReviewReport> => {\n const configuration = getConfiguration(configOptions);\n const appLogger = getAppLogger({ log: { ...configuration.log, prefix: '' } });\n\n const baseText = await readFile(baseFilePath, 'utf-8');\n const targetText = existsSync(outputFilePath)\n ? await readFile(outputFilePath, 'utf-8').catch(() => '')\n : '';\n\n const report = buildReviewReport({ baseText, targetText, changedLines });\n\n const formatted = formatReviewReport(report, {\n baseLabel: formatLocale(baseLocale),\n targetLabel: formatLocale(locale),\n });\n\n appLogger(`${formatPath(baseFilePath)} → ${formatLocale(locale)}`);\n for (const line of formatted.split('\\n')) {\n appLogger(line);\n }\n\n return report;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,sBAAsB,OACjC,cACA,gBACA,QACA,YACA,eACA,iBAC0B;CAE1B,MAAM,sDAAyB,EAAE,KAAK;EAAE,+CADD,cACiB,CAAC;EAAK,QAAQ;EAAI,EAAE,CAAC;CAO7E,MAAM,6DAA2B;EAAE,+CALH,cAAc,QAAQ;EAKT,oCAJf,eAAe,GACzC,qCAAe,gBAAgB,QAAQ,CAAC,YAAY,GAAG,GACvD;EAEqD;EAAc,CAAC;CAExE,MAAM,iEAA+B,QAAQ;EAC3C,sDAAwB,WAAW;EACnC,wDAA0B,OAAO;EAClC,CAAC;AAEF,WAAU,4CAAc,aAAa,CAAC,gDAAkB,OAAO,GAAG;AAClE,MAAK,MAAM,QAAQ,UAAU,MAAM,KAAK,CACtC,WAAU,KAAK;AAGjB,QAAO"}
@@ -0,0 +1,44 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/utils/formatLineRanges.ts
4
+ /**
5
+ * Formats a list of line numbers into a compact, human-readable string where
6
+ * runs of consecutive lines are collapsed into ranges.
7
+ *
8
+ * The input is sorted and de-duplicated first, so callers don't need to
9
+ * pre-process it. A run of a single line is printed as the bare number; a run
10
+ * of two or more consecutive lines is printed as `start-end`.
11
+ *
12
+ * @example
13
+ * formatLineRanges([2, 3, 4, 5, 333, 412, 413, 414]);
14
+ * // → '2-5, 333, 412-414'
15
+ *
16
+ * @param lineNumbers - The (possibly unsorted, possibly duplicated) line numbers.
17
+ * @param separator - String inserted between groups. Defaults to `', '`.
18
+ * @returns The grouped string, or an empty string when no lines are provided.
19
+ */
20
+ const formatLineRanges = (lineNumbers, separator = ", ") => {
21
+ const sortedUniqueLines = [...new Set(lineNumbers)].sort((a, b) => a - b);
22
+ if (sortedUniqueLines.length === 0) return "";
23
+ const groups = [];
24
+ let rangeStart = sortedUniqueLines[0];
25
+ let rangeEnd = rangeStart;
26
+ const pushGroup = () => {
27
+ groups.push(rangeStart === rangeEnd ? `${rangeStart}` : `${rangeStart}-${rangeEnd}`);
28
+ };
29
+ for (const lineNumber of sortedUniqueLines.slice(1)) {
30
+ if (lineNumber === rangeEnd + 1) {
31
+ rangeEnd = lineNumber;
32
+ continue;
33
+ }
34
+ pushGroup();
35
+ rangeStart = lineNumber;
36
+ rangeEnd = lineNumber;
37
+ }
38
+ pushGroup();
39
+ return groups.join(separator);
40
+ };
41
+
42
+ //#endregion
43
+ exports.formatLineRanges = formatLineRanges;
44
+ //# sourceMappingURL=formatLineRanges.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatLineRanges.cjs","names":[],"sources":["../../../src/utils/formatLineRanges.ts"],"sourcesContent":["/**\n * Formats a list of line numbers into a compact, human-readable string where\n * runs of consecutive lines are collapsed into ranges.\n *\n * The input is sorted and de-duplicated first, so callers don't need to\n * pre-process it. A run of a single line is printed as the bare number; a run\n * of two or more consecutive lines is printed as `start-end`.\n *\n * @example\n * formatLineRanges([2, 3, 4, 5, 333, 412, 413, 414]);\n * // → '2-5, 333, 412-414'\n *\n * @param lineNumbers - The (possibly unsorted, possibly duplicated) line numbers.\n * @param separator - String inserted between groups. Defaults to `', '`.\n * @returns The grouped string, or an empty string when no lines are provided.\n */\nexport const formatLineRanges = (\n lineNumbers: number[],\n separator = ', '\n): string => {\n const sortedUniqueLines = [...new Set(lineNumbers)].sort((a, b) => a - b);\n\n if (sortedUniqueLines.length === 0) return '';\n\n const groups: string[] = [];\n let rangeStart = sortedUniqueLines[0]!;\n let rangeEnd = rangeStart;\n\n const pushGroup = (): void => {\n groups.push(\n rangeStart === rangeEnd ? `${rangeStart}` : `${rangeStart}-${rangeEnd}`\n );\n };\n\n for (const lineNumber of sortedUniqueLines.slice(1)) {\n if (lineNumber === rangeEnd + 1) {\n // Still inside the current consecutive run.\n rangeEnd = lineNumber;\n continue;\n }\n\n // Gap detected: close the current run and start a new one.\n pushGroup();\n rangeStart = lineNumber;\n rangeEnd = lineNumber;\n }\n\n pushGroup();\n\n return groups.join(separator);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,MAAa,oBACX,aACA,YAAY,SACD;CACX,MAAM,oBAAoB,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;AAEzE,KAAI,kBAAkB,WAAW,EAAG,QAAO;CAE3C,MAAM,SAAmB,EAAE;CAC3B,IAAI,aAAa,kBAAkB;CACnC,IAAI,WAAW;CAEf,MAAM,kBAAwB;AAC5B,SAAO,KACL,eAAe,WAAW,GAAG,eAAe,GAAG,WAAW,GAAG,WAC9D;;AAGH,MAAK,MAAM,cAAc,kBAAkB,MAAM,EAAE,EAAE;AACnD,MAAI,eAAe,WAAW,GAAG;AAE/B,cAAW;AACX;;AAIF,aAAW;AACX,eAAa;AACb,aAAW;;AAGb,YAAW;AAEX,QAAO,OAAO,KAAK,UAAU"}
package/dist/esm/cli.mjs CHANGED
@@ -166,7 +166,10 @@ const setAPI = () => {
166
166
  /**
167
167
  * INIT
168
168
  */
169
- const initCmd = program.command("init").description("Initialize Intlayer in the project").option("--project-root [projectRoot]", "Project root directory").option("--no-gitignore", "Do not add .intlayer to .gitignore").action((options) => init(options.projectRoot, { noGitignore: options.gitignore === false }));
169
+ const initCmd = program.command("init").description("Initialize Intlayer in the project").option("--project-root [projectRoot]", "Project root directory").option("--no-gitignore", "Do not add .intlayer to .gitignore").option("--no-github-actions", "Do not scaffold the fill and test GitHub Actions workflows").action((options) => init(options.projectRoot, {
170
+ noGitignore: options.gitignore === false,
171
+ noGithubActions: options.githubActions === false
172
+ }));
170
173
  initCmd.command("skills").description("Initialize Intlayer skills in the project").option("--project-root [projectRoot]", "Project root directory").action((options) => initSkills(options.projectRoot));
171
174
  initCmd.command("mcp").description("Initialize Intlayer MCP server in the project").option("--project-root [projectRoot]", "Project root directory").action((options) => initMCP(options.projectRoot));
172
175
  /**
@@ -413,7 +416,7 @@ const setAPI = () => {
413
416
  skipIfModifiedAfter: options.skipIfModifiedAfter,
414
417
  skipIfExists: options.skipIfExists
415
418
  }));
416
- const reviewProgram = docProgram.command("review").description("Review the documentation");
419
+ const reviewProgram = docProgram.command("review").description("Review the documentation").option("--log", "Log-only mode. Do not translate with AI; instead log the blocks that need attention (with line numbers and content) for the base and target locales, to help another agent generate the translations.");
417
420
  applyConfigOptions(reviewProgram);
418
421
  applyAIOptions(reviewProgram);
419
422
  applyGitOptions(reviewProgram);
@@ -430,7 +433,8 @@ const setAPI = () => {
430
433
  customInstructions: options.customInstructions,
431
434
  skipIfModifiedBefore: options.skipIfModifiedBefore,
432
435
  skipIfModifiedAfter: options.skipIfModifiedAfter,
433
- skipIfExists: options.skipIfExists
436
+ skipIfExists: options.skipIfExists,
437
+ log: options.log
434
438
  }));
435
439
  const searchProgram = docProgram.command("search").description("Search the documentation").argument("<query>", "Search query").option("--limit [limit]", "Limit the number of results", "10");
436
440
  applyConfigOptions(searchProgram);
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["pathDirname"],"sources":["../../src/cli.ts"],"sourcesContent":["import { dirname as pathDirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport type { DiffMode, ListGitFilesOptions } from '@intlayer/chokidar/cli';\nimport { setPrefix } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { CustomIntlayerConfig } from '@intlayer/types/config';\nimport { Command } from 'commander';\nimport { login } from './auth/login';\nimport { build } from './build';\nimport { bundle } from './bundle';\nimport { runCI } from './ci';\nimport { getConfig } from './config';\nimport { startEditor } from './editor';\nimport { extract } from './extract';\nimport { type FillOptions, fill } from './fill/fill';\nimport { init } from './init';\nimport { initMCP } from './initMCP';\nimport { initSkills } from './initSkills';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { listProjectsCommand } from './listProjects';\nimport { liveSync } from './liveSync';\nimport { pull } from './pull';\nimport { push } from './push/push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc/reviewDoc';\nimport { scan } from './scan';\nimport { searchDoc } from './searchDoc';\nimport { testMissingTranslations } from './test';\nimport { translateDoc } from './translateDoc/translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\nimport { watchContentDeclaration } from './watch';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nconst isESModule = typeof import.meta.url === 'string';\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose (default to true using CLI)'],\n ['--prefix [prefix]', 'Prefix'],\n];\n\nconst configurationOptions = [\n ['--env-file [envFile]', 'Environment file'],\n ['-e, --env [env]', 'Environment'],\n ['--base-dir [baseDir]', 'Base directory'],\n ['--no-cache [noCache]', 'No cache'],\n ...logOptions,\n];\n\nconst aiOptions = [\n ['--provider [provider]', 'Provider'],\n ['--temperature [temperature]', 'Temperature'],\n ['--model [model]', 'Model'],\n ['--api-key [apiKey]', 'Provider API key'],\n ['--custom-prompt [prompt]', 'Custom prompt'],\n ['--application-context [applicationContext]', 'Application context'],\n ['--data-serialization [dataSerialization]', 'Data serialization'],\n];\n\nconst gitOptions = [\n ['--git-diff [gitDiff]', 'Git diff mode - Check git diff between two refs'],\n ['--git-diff-base [gitDiffBase]', 'Git diff base ref'],\n ['--git-diff-current [gitDiffCurrent]', 'Git diff current ref'],\n ['--uncommitted [uncommitted]', 'Uncommitted'],\n ['--unpushed [unpushed]', 'Unpushed'],\n ['--untracked [untracked]', 'Untracked'],\n];\n\nconst extractKeysFromOptions = (options: object, keys: string[]) =>\n keys.filter((key) => options[key as keyof typeof options] !== undefined);\n\n/**\n * Helper functions to apply common options to commands\n */\nconst applyOptions = (command: Command, options: string[][]) => {\n options.forEach(([flag, description]) => {\n command.option(flag, description);\n });\n return command;\n};\n\nconst removeUndefined = <T extends Record<string, any>>(obj: T): T =>\n Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined)\n ) as T;\n\nconst applyConfigOptions = (command: Command) =>\n applyOptions(command, configurationOptions);\nconst applyAIOptions = (command: Command) => applyOptions(command, aiOptions);\nconst applyGitOptions = (command: Command) => applyOptions(command, gitOptions);\n\nconst extractAiOptions = (options: AIOptions): AIOptions | undefined => {\n const {\n apiKey,\n provider,\n model,\n temperature,\n applicationContext,\n customPrompt,\n dataSerialization,\n } = options;\n\n const configuration = getConfiguration();\n\n const { ai } = configuration;\n\n return removeUndefined({\n ...ai,\n apiKey: apiKey ?? configuration.ai?.apiKey,\n provider: provider ?? (configuration.ai?.provider as AIOptions['provider']),\n model: model ?? configuration.ai?.model,\n temperature: temperature ?? configuration.ai?.temperature,\n applicationContext:\n applicationContext ?? configuration.ai?.applicationContext,\n customPrompt: customPrompt ?? (configuration.ai as any)?.customPrompt,\n dataSerialization: dataSerialization ?? configuration.ai?.dataSerialization,\n });\n};\n\ntype GitOptions = {\n gitDiff?: boolean;\n gitDiffBase?: string;\n gitDiffCurrent?: string;\n uncommitted?: boolean;\n unpushed?: boolean;\n untracked?: boolean;\n};\n\nconst gitOptionKeys: (keyof GitOptions)[] = [\n 'gitDiff',\n 'gitDiffBase',\n 'gitDiffCurrent',\n 'uncommitted',\n 'unpushed',\n 'untracked',\n];\n\nconst extractGitOptions = (\n options: GitOptions\n): ListGitFilesOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(options, gitOptionKeys);\n\n const isOptionEmpty = filteredOptions.length === 0;\n\n if (isOptionEmpty) return undefined;\n\n const {\n gitDiff,\n gitDiffBase,\n gitDiffCurrent,\n uncommitted,\n unpushed,\n untracked,\n } = options;\n\n const mode = [\n gitDiff && 'gitDiff',\n uncommitted && 'uncommitted',\n unpushed && 'unpushed',\n untracked && 'untracked',\n ].filter(Boolean) as DiffMode[];\n\n return removeUndefined({\n mode,\n baseRef: gitDiffBase,\n currentRef: gitDiffCurrent,\n absolute: true,\n });\n};\n\ntype LogOptions = {\n prefix?: string;\n verbose?: boolean;\n};\n\nexport type ConfigurationOptions = {\n baseDir?: string;\n env?: string;\n envFile?: string;\n noCache?: boolean;\n checkTypes?: boolean;\n} & LogOptions;\n\nconst configurationOptionKeys: (keyof ConfigurationOptions)[] = [\n 'baseDir',\n 'env',\n 'envFile',\n 'verbose',\n 'prefix',\n 'checkTypes',\n];\n\nconst extractConfigOptions = (\n options: ConfigurationOptions & { with?: string }\n): GetConfigurationOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(\n options,\n configurationOptionKeys\n );\n\n const isOptionEmpty = filteredOptions.length === 0;\n\n if (isOptionEmpty) {\n return undefined;\n }\n\n const { baseDir, env, envFile, verbose, noCache, checkTypes } = options;\n\n const log = removeUndefined({\n mode:\n typeof verbose !== 'undefined'\n ? verbose\n ? 'verbose'\n : 'default'\n : undefined,\n });\n\n const build = removeUndefined({\n checkTypes,\n });\n\n const override: CustomIntlayerConfig = removeUndefined({\n log:\n Object.keys(log).length > 0\n ? (log as CustomIntlayerConfig['log'])\n : undefined,\n build: Object.keys(build).length > 0 ? build : undefined,\n });\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override: Object.keys(override).length > 0 ? override : undefined,\n cache: typeof noCache !== 'undefined' ? !noCache : undefined,\n });\n};\n\n/**\n * Set the API for the CLI\n *\n * Example of commands:\n *\n * npm run intlayer build --watch\n * npm run intlayer push --dictionaries id1 id2 id3 --deleteLocaleDir\n */\nexport const setAPI = (): Command => {\n const isWithCommand = process.argv.includes('--with');\n\n if (!isWithCommand) {\n setPrefix('');\n }\n\n const program = new Command();\n\n program.version(packageJson.version!).description('Intlayer CLI');\n\n // Explicit version subcommand for convenience: `npx intlayer version`\n program\n .command('version')\n .description('Print the Intlayer CLI version')\n .action(() => {\n // Prefer the resolved package.json version; fallback to unknown\n // Keeping output minimal to align with common CLI behavior\n console.log(packageJson.version ?? 'unknown');\n });\n\n /**\n * AUTH\n */\n const loginCmd = program\n .command('login')\n .description('Login to Intlayer')\n .option('--cms-url [cmsUrl]', 'CMS URL');\n\n applyConfigOptions(loginCmd);\n\n loginCmd.action((options) => {\n const configOptions = extractConfigOptions(options) ?? {\n override: {\n log: {\n prefix: '',\n mode: 'verbose',\n },\n },\n };\n\n return login({\n cmsUrl: options.cmsUrl,\n configOptions,\n });\n });\n\n /**\n * INIT\n */\n const initCmd = program\n .command('init')\n .description('Initialize Intlayer in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .option('--no-gitignore', 'Do not add .intlayer to .gitignore')\n .action((options) =>\n init(options.projectRoot, {\n noGitignore: options.gitignore === false,\n })\n );\n\n initCmd\n .command('skills')\n .description('Initialize Intlayer skills in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => initSkills(options.projectRoot));\n\n initCmd\n .command('mcp')\n .description('Initialize Intlayer MCP server in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => initMCP(options.projectRoot));\n\n /**\n * DICTIONARIES\n */\n\n const dictionariesProgram = program\n .command('dictionary')\n .alias('dictionaries')\n .alias('dic')\n .description('Dictionaries operations');\n\n // Dictionary build command\n const buildOptions = {\n description: 'Build the dictionaries',\n options: [\n ['-w, --watch', 'Watch for changes'],\n ['--skip-prepare', 'Skip the prepare step'],\n ['--with [with...]', 'Start command in parallel with the build'],\n ['--check-types', 'Check TypeScript type and log errors'],\n ],\n };\n\n // Add build command to dictionaries program\n const dictionariesBuildCmd = dictionariesProgram\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(dictionariesBuildCmd, buildOptions.options);\n applyConfigOptions(dictionariesBuildCmd);\n dictionariesBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootBuildCmd = program\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(rootBuildCmd, buildOptions.options);\n applyConfigOptions(rootBuildCmd);\n rootBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const watchOptions = {\n description: 'Watch the dictionaries changes',\n options: [['--with [with...]', 'Start command in parallel with the build']],\n };\n\n // Add build command to dictionaries program\n const dictionariesWatchCmd = dictionariesProgram\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(dictionariesWatchCmd, watchOptions.options);\n applyConfigOptions(dictionariesWatchCmd);\n dictionariesWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootWatchCmd = program\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(rootWatchCmd, watchOptions.options);\n applyConfigOptions(rootWatchCmd);\n rootWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary pull command\n const pullOptions = {\n description: 'Pull dictionaries from the server',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to pull'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to pull (alias for --dictionaries)',\n ],\n ['--new-dictionaries-path [path]', 'Path to save the new dictionaries'],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--newDictionariesPath [path]',\n '[alias] Path to save the new dictionaries',\n ],\n ],\n };\n\n // Add pull command to dictionaries program\n const dictionariesPullCmd = dictionariesProgram\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(dictionariesPullCmd, pullOptions.options);\n applyConfigOptions(dictionariesPullCmd);\n dictionariesPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: {\n ...options.configOptions,\n baseDir: options.baseDir,\n },\n });\n });\n\n // Add pull command to root program as well\n const rootPullCmd = program\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(rootPullCmd, pullOptions.options);\n applyConfigOptions(rootPullCmd);\n rootPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary push command\n const pushOptions = {\n description:\n 'Push all dictionaries. Create or update the pushed dictionaries',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to push'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to push (alias for --dictionaries)',\n ],\n [\n '-r, --delete-locale-dictionary',\n 'Delete the local dictionaries after pushing',\n ],\n [\n '-k, --keep-locale-dictionary',\n 'Keep the local dictionaries after pushing',\n ],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--deleteLocaleDictionary',\n '[alias] Delete the local dictionaries after pushing',\n ],\n [\n '--keepLocaleDictionary',\n '[alias] Keep the local dictionaries after pushing',\n ],\n [\n '--build [build]',\n 'Build the dictionaries before pushing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build',\n ],\n ],\n };\n\n // Add push command to dictionaries program\n const dictionariesPushCmd = dictionariesProgram\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(dictionariesPushCmd, pushOptions.options);\n applyConfigOptions(dictionariesPushCmd);\n applyGitOptions(dictionariesPushCmd);\n\n dictionariesPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n // Add push command to root program as well\n const rootPushCmd = program\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(rootPushCmd, pushOptions.options);\n applyConfigOptions(rootPushCmd);\n applyGitOptions(rootPushCmd);\n\n rootPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * CONFIGURATION\n */\n\n // Define the parent command\n const configurationProgram = program\n .command('configuration')\n .alias('config')\n .alias('conf')\n .description('Configuration operations');\n\n const configGetCmd = configurationProgram\n .command('get')\n .description('Get the configuration');\n\n applyConfigOptions(configGetCmd);\n configGetCmd.action((options) => {\n getConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Define the `push config` subcommand and add it to the `push` command\n const configPushCmd = configurationProgram\n .command('push')\n .description('Push the configuration');\n\n applyConfigOptions(configPushCmd);\n configPushCmd.action((options) => {\n pushConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n /**\n * PROJECTS\n */\n\n const projectsProgram = program\n .command('projects')\n .alias('project')\n .description('List Intlayer projects');\n\n const projectsListCmd = projectsProgram\n .command('list')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--json', 'Output the results as JSON');\n\n projectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n });\n });\n\n // Add alias for projects list command at root level\n const rootProjectsListCmd = program\n .command('projects-list')\n .alias('pl')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--absolute', 'Output the results as absolute paths')\n .option('--json', 'Output the results as JSON');\n\n rootProjectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n /**\n * CONTENT DECLARATION\n */\n\n const contentProgram = program\n .command('content')\n .description('Content declaration operations');\n\n contentProgram\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n // Add alias for content list command\n program\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n const testProgram = contentProgram\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(testProgram);\n testProgram.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add alias for content test command\n const rootTestCmd = program\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(rootTestCmd);\n rootTestCmd.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const fillProgram = program\n .command('fill')\n .description('Fill the dictionaries')\n .option('-f, --file [files...]', 'List of Dictionary files to fill')\n .option('--source-locale [sourceLocale]', 'Source locale to translate from')\n .option(\n '--output-locales [outputLocales...]',\n 'Target locales to translate to'\n )\n .option(\n '--mode [mode]',\n 'Fill mode: complete, review. Complete will fill all missing content, review will fill missing content and review existing keys',\n 'complete'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--key [keys...]',\n 'Filter dictionaries based on keys (alias for --keys)'\n )\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--excluded-key [excludedKeys...]',\n 'Filter out dictionaries based on keys (alias for --excluded-keys)'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n )\n .option(\n '--build [build]',\n 'Build the dictionaries before filling to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n )\n .option(\n '--skip-metadata',\n 'Skip filling missing metadata (description, title, tags) for dictionaries'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) => {\n // Merge key aliases\n const keys = [...(options.keys ?? []), ...(options.key ?? [])];\n const excludedKeys = [\n ...(options.excludedKeys ?? []),\n ...(options.excludedKey ?? []),\n ];\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n return fill({\n ...options,\n keys: keys.length > 0 ? keys : undefined,\n excludedKeys: excludedKeys.length > 0 ? excludedKeys : undefined,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * DOCS\n */\n\n const docParams = [\n ['--doc-pattern [docPattern...]', 'Documentation pattern'],\n [\n '--excluded-glob-pattern [excludedGlobPattern...]',\n 'Excluded glob pattern',\n ],\n [\n '--nb-simultaneous-file-processed [nbSimultaneousFileProcessed]',\n 'Number of simultaneous file processed',\n ],\n ['--locales [locales...]', 'Locales'],\n ['--base-locale [baseLocale]', 'Base locale'],\n [\n '--custom-instructions [customInstructions]',\n 'Custom instructions added to the prompt. Usefull to apply specific rules regarding formatting, urls translation, etc.',\n ],\n [\n '--skip-if-modified-before [skipIfModifiedBefore]',\n 'Skip the file if it has been modified before the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n [\n '--skip-if-modified-after [skipIfModifiedAfter]',\n 'Skip the file if it has been modified within the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n ['--skip-if-exists', 'Skip the file if it already exists'],\n ];\n\n const docProgram = program\n .command('doc')\n .description('Documentation operations');\n\n const translateProgram = docProgram\n .command('translate')\n .description('Translate the documentation');\n\n applyConfigOptions(translateProgram);\n applyAIOptions(translateProgram);\n applyGitOptions(translateProgram);\n applyOptions(translateProgram, docParams);\n\n translateProgram.action((options) =>\n translateDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n const reviewProgram = docProgram\n .command('review')\n .description('Review the documentation');\n\n applyConfigOptions(reviewProgram);\n applyAIOptions(reviewProgram);\n applyGitOptions(reviewProgram);\n applyOptions(reviewProgram, docParams);\n\n reviewProgram.action((options) =>\n reviewDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n const searchProgram = docProgram\n .command('search')\n .description('Search the documentation')\n .argument('<query>', 'Search query')\n .option('--limit [limit]', 'Limit the number of results', '10');\n\n applyConfigOptions(searchProgram);\n\n searchProgram.action((query, options) =>\n searchDoc({\n query,\n limit: options.limit ? parseInt(options.limit, 10) : 10,\n configOptions: extractConfigOptions(options),\n })\n );\n\n /**\n * LIVE SYNC\n */\n\n const liveOptions = [\n ['--with [with...]', 'Start command in parallel with the live sync'],\n ];\n\n const liveCmd = program\n .command('live')\n .description(\n 'Live sync - Watch for changes made on the CMS and update the application content accordingly'\n );\n\n applyOptions(liveCmd, liveOptions);\n applyConfigOptions(liveCmd);\n\n liveCmd.action((options) => liveSync(options));\n\n /**\n * EDITOR\n */\n\n const editorProgram = program\n .command('editor')\n .description('Visual editor operations');\n\n const editorStartCmd = editorProgram\n .command('start')\n .description('Start the Intlayer visual editor');\n\n applyConfigOptions(editorStartCmd);\n\n editorStartCmd.action((options) => {\n startEditor({\n env: options.env,\n envFile: options.envFile,\n });\n });\n\n /**\n * EXTRACT\n */\n const extractProgram = program\n .command('extract')\n .alias('ext')\n .description(\n 'Extract strings from components to be placed in a .content file close to the component'\n );\n\n extractProgram\n .option('-f, --file [files...]', 'List of files to extract')\n .option('--code-only', 'Only extract the component code', false)\n .option('--declaration-only', 'Only generate content declaration', false)\n .action((options) => {\n extract({\n files: options.file,\n configOptions: extractConfigOptions(options),\n codeOnly: options.codeOnly,\n declarationOnly: options.declarationOnly,\n });\n });\n\n /**\n * STANDALONE\n */\n const bundleCmd = program\n .command('standalone')\n .description('Create a standalone bundle of the application content')\n .option(\n '-o, --outfile [outfile]',\n 'Output file for the bundle',\n 'intlayer-bundle.js'\n )\n .option('--packages [packages...]', 'List of packages to bundle')\n .option('--version [version]', 'Version of the packages to bundle')\n .option('--minify', 'Minify the output')\n .option('--platform [platform]', 'Target platform', 'browser')\n .option('--format [format]', 'Output format', 'esm')\n .action((options) => {\n bundle({\n outfile: options.outfile,\n bundlePackages: options.packages,\n version: options.version,\n minify: options.minify,\n platform: options.platform,\n format: options.format,\n configOptions: extractConfigOptions(options),\n });\n });\n\n applyConfigOptions(bundleCmd);\n\n /**\n * SCAN\n */\n const scanCmd = program\n .command('scan')\n .description(\n 'Scan a website to measure its page size and audit its i18n / SEO health'\n )\n .argument('<url>', 'URL of the website to scan')\n .option('--no-deep', 'Disable the deeper puppeteer-based render scan')\n .option('--json', 'Output the results as JSON');\n\n applyConfigOptions(scanCmd);\n\n scanCmd.action((url, options) =>\n scan(url, {\n deep: options.deep,\n json: options.json,\n configOptions: extractConfigOptions(options),\n })\n );\n\n program.parse(process.argv);\n\n /**\n * CI / AUTOMATION\n *\n * Used to iterate over all projects in a monorepo, and help to parse secrets\n */\n program\n .command('ci')\n .description(\n 'Run Intlayer commands with auto-injected credentials from INTLAYER_PROJECT_CREDENTIALS. Detects current project or iterates over all projects.'\n )\n .argument(\n '<command...>',\n 'The intlayer command to execute (e.g., \"fill\", \"push\")'\n )\n .allowUnknownOption() // Allows passing flags like --verbose to the subcommand\n .action((args) => {\n runCI(args);\n });\n\n return program;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["pathDirname"],"sources":["../../src/cli.ts"],"sourcesContent":["import { dirname as pathDirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AIOptions as BaseAIOptions } from '@intlayer/api';\nimport type { DiffMode, ListGitFilesOptions } from '@intlayer/chokidar/cli';\nimport { setPrefix } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { CustomIntlayerConfig } from '@intlayer/types/config';\nimport { Command } from 'commander';\nimport { login } from './auth/login';\nimport { build } from './build';\nimport { bundle } from './bundle';\nimport { runCI } from './ci';\nimport { getConfig } from './config';\nimport { startEditor } from './editor';\nimport { extract } from './extract';\nimport { type FillOptions, fill } from './fill/fill';\nimport { init } from './init';\nimport { initMCP } from './initMCP';\nimport { initSkills } from './initSkills';\nimport { listContentDeclaration } from './listContentDeclaration';\nimport { listProjectsCommand } from './listProjects';\nimport { liveSync } from './liveSync';\nimport { pull } from './pull';\nimport { push } from './push/push';\nimport { pushConfig } from './pushConfig';\nimport { reviewDoc } from './reviewDoc/reviewDoc';\nimport { scan } from './scan';\nimport { searchDoc } from './searchDoc';\nimport { testMissingTranslations } from './test';\nimport { translateDoc } from './translateDoc/translateDoc';\nimport { getParentPackageJSON } from './utils/getParentPackageJSON';\nimport { watchContentDeclaration } from './watch';\n\n// Extended AI options to include customPrompt\ntype AIOptions = BaseAIOptions & {\n customPrompt?: string;\n};\n\nconst isESModule = typeof import.meta.url === 'string';\n\nexport const dirname = isESModule\n ? pathDirname(fileURLToPath(import.meta.url))\n : __dirname;\n\nconst packageJson = getParentPackageJSON(dirname);\n\nconst logOptions = [\n ['--verbose', 'Verbose (default to true using CLI)'],\n ['--prefix [prefix]', 'Prefix'],\n];\n\nconst configurationOptions = [\n ['--env-file [envFile]', 'Environment file'],\n ['-e, --env [env]', 'Environment'],\n ['--base-dir [baseDir]', 'Base directory'],\n ['--no-cache [noCache]', 'No cache'],\n ...logOptions,\n];\n\nconst aiOptions = [\n ['--provider [provider]', 'Provider'],\n ['--temperature [temperature]', 'Temperature'],\n ['--model [model]', 'Model'],\n ['--api-key [apiKey]', 'Provider API key'],\n ['--custom-prompt [prompt]', 'Custom prompt'],\n ['--application-context [applicationContext]', 'Application context'],\n ['--data-serialization [dataSerialization]', 'Data serialization'],\n];\n\nconst gitOptions = [\n ['--git-diff [gitDiff]', 'Git diff mode - Check git diff between two refs'],\n ['--git-diff-base [gitDiffBase]', 'Git diff base ref'],\n ['--git-diff-current [gitDiffCurrent]', 'Git diff current ref'],\n ['--uncommitted [uncommitted]', 'Uncommitted'],\n ['--unpushed [unpushed]', 'Unpushed'],\n ['--untracked [untracked]', 'Untracked'],\n];\n\nconst extractKeysFromOptions = (options: object, keys: string[]) =>\n keys.filter((key) => options[key as keyof typeof options] !== undefined);\n\n/**\n * Helper functions to apply common options to commands\n */\nconst applyOptions = (command: Command, options: string[][]) => {\n options.forEach(([flag, description]) => {\n command.option(flag, description);\n });\n return command;\n};\n\nconst removeUndefined = <T extends Record<string, any>>(obj: T): T =>\n Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined)\n ) as T;\n\nconst applyConfigOptions = (command: Command) =>\n applyOptions(command, configurationOptions);\nconst applyAIOptions = (command: Command) => applyOptions(command, aiOptions);\nconst applyGitOptions = (command: Command) => applyOptions(command, gitOptions);\n\nconst extractAiOptions = (options: AIOptions): AIOptions | undefined => {\n const {\n apiKey,\n provider,\n model,\n temperature,\n applicationContext,\n customPrompt,\n dataSerialization,\n } = options;\n\n const configuration = getConfiguration();\n\n const { ai } = configuration;\n\n return removeUndefined({\n ...ai,\n apiKey: apiKey ?? configuration.ai?.apiKey,\n provider: provider ?? (configuration.ai?.provider as AIOptions['provider']),\n model: model ?? configuration.ai?.model,\n temperature: temperature ?? configuration.ai?.temperature,\n applicationContext:\n applicationContext ?? configuration.ai?.applicationContext,\n customPrompt: customPrompt ?? (configuration.ai as any)?.customPrompt,\n dataSerialization: dataSerialization ?? configuration.ai?.dataSerialization,\n });\n};\n\ntype GitOptions = {\n gitDiff?: boolean;\n gitDiffBase?: string;\n gitDiffCurrent?: string;\n uncommitted?: boolean;\n unpushed?: boolean;\n untracked?: boolean;\n};\n\nconst gitOptionKeys: (keyof GitOptions)[] = [\n 'gitDiff',\n 'gitDiffBase',\n 'gitDiffCurrent',\n 'uncommitted',\n 'unpushed',\n 'untracked',\n];\n\nconst extractGitOptions = (\n options: GitOptions\n): ListGitFilesOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(options, gitOptionKeys);\n\n const isOptionEmpty = filteredOptions.length === 0;\n\n if (isOptionEmpty) return undefined;\n\n const {\n gitDiff,\n gitDiffBase,\n gitDiffCurrent,\n uncommitted,\n unpushed,\n untracked,\n } = options;\n\n const mode = [\n gitDiff && 'gitDiff',\n uncommitted && 'uncommitted',\n unpushed && 'unpushed',\n untracked && 'untracked',\n ].filter(Boolean) as DiffMode[];\n\n return removeUndefined({\n mode,\n baseRef: gitDiffBase,\n currentRef: gitDiffCurrent,\n absolute: true,\n });\n};\n\ntype LogOptions = {\n prefix?: string;\n verbose?: boolean;\n};\n\nexport type ConfigurationOptions = {\n baseDir?: string;\n env?: string;\n envFile?: string;\n noCache?: boolean;\n checkTypes?: boolean;\n} & LogOptions;\n\nconst configurationOptionKeys: (keyof ConfigurationOptions)[] = [\n 'baseDir',\n 'env',\n 'envFile',\n 'verbose',\n 'prefix',\n 'checkTypes',\n];\n\nconst extractConfigOptions = (\n options: ConfigurationOptions & { with?: string }\n): GetConfigurationOptions | undefined => {\n const filteredOptions = extractKeysFromOptions(\n options,\n configurationOptionKeys\n );\n\n const isOptionEmpty = filteredOptions.length === 0;\n\n if (isOptionEmpty) {\n return undefined;\n }\n\n const { baseDir, env, envFile, verbose, noCache, checkTypes } = options;\n\n const log = removeUndefined({\n mode:\n typeof verbose !== 'undefined'\n ? verbose\n ? 'verbose'\n : 'default'\n : undefined,\n });\n\n const build = removeUndefined({\n checkTypes,\n });\n\n const override: CustomIntlayerConfig = removeUndefined({\n log:\n Object.keys(log).length > 0\n ? (log as CustomIntlayerConfig['log'])\n : undefined,\n build: Object.keys(build).length > 0 ? build : undefined,\n });\n\n return removeUndefined({\n baseDir,\n env,\n envFile,\n override: Object.keys(override).length > 0 ? override : undefined,\n cache: typeof noCache !== 'undefined' ? !noCache : undefined,\n });\n};\n\n/**\n * Set the API for the CLI\n *\n * Example of commands:\n *\n * npm run intlayer build --watch\n * npm run intlayer push --dictionaries id1 id2 id3 --deleteLocaleDir\n */\nexport const setAPI = (): Command => {\n const isWithCommand = process.argv.includes('--with');\n\n if (!isWithCommand) {\n setPrefix('');\n }\n\n const program = new Command();\n\n program.version(packageJson.version!).description('Intlayer CLI');\n\n // Explicit version subcommand for convenience: `npx intlayer version`\n program\n .command('version')\n .description('Print the Intlayer CLI version')\n .action(() => {\n // Prefer the resolved package.json version; fallback to unknown\n // Keeping output minimal to align with common CLI behavior\n console.log(packageJson.version ?? 'unknown');\n });\n\n /**\n * AUTH\n */\n const loginCmd = program\n .command('login')\n .description('Login to Intlayer')\n .option('--cms-url [cmsUrl]', 'CMS URL');\n\n applyConfigOptions(loginCmd);\n\n loginCmd.action((options) => {\n const configOptions = extractConfigOptions(options) ?? {\n override: {\n log: {\n prefix: '',\n mode: 'verbose',\n },\n },\n };\n\n return login({\n cmsUrl: options.cmsUrl,\n configOptions,\n });\n });\n\n /**\n * INIT\n */\n const initCmd = program\n .command('init')\n .description('Initialize Intlayer in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .option('--no-gitignore', 'Do not add .intlayer to .gitignore')\n .option(\n '--no-github-actions',\n 'Do not scaffold the fill and test GitHub Actions workflows'\n )\n .action((options) =>\n init(options.projectRoot, {\n noGitignore: options.gitignore === false,\n noGithubActions: options.githubActions === false,\n })\n );\n\n initCmd\n .command('skills')\n .description('Initialize Intlayer skills in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => initSkills(options.projectRoot));\n\n initCmd\n .command('mcp')\n .description('Initialize Intlayer MCP server in the project')\n .option('--project-root [projectRoot]', 'Project root directory')\n .action((options) => initMCP(options.projectRoot));\n\n /**\n * DICTIONARIES\n */\n\n const dictionariesProgram = program\n .command('dictionary')\n .alias('dictionaries')\n .alias('dic')\n .description('Dictionaries operations');\n\n // Dictionary build command\n const buildOptions = {\n description: 'Build the dictionaries',\n options: [\n ['-w, --watch', 'Watch for changes'],\n ['--skip-prepare', 'Skip the prepare step'],\n ['--with [with...]', 'Start command in parallel with the build'],\n ['--check-types', 'Check TypeScript type and log errors'],\n ],\n };\n\n // Add build command to dictionaries program\n const dictionariesBuildCmd = dictionariesProgram\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(dictionariesBuildCmd, buildOptions.options);\n applyConfigOptions(dictionariesBuildCmd);\n dictionariesBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootBuildCmd = program\n .command('build')\n .description(buildOptions.description);\n\n applyOptions(rootBuildCmd, buildOptions.options);\n applyConfigOptions(rootBuildCmd);\n rootBuildCmd.action((options) => {\n build({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const watchOptions = {\n description: 'Watch the dictionaries changes',\n options: [['--with [with...]', 'Start command in parallel with the build']],\n };\n\n // Add build command to dictionaries program\n const dictionariesWatchCmd = dictionariesProgram\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(dictionariesWatchCmd, watchOptions.options);\n applyConfigOptions(dictionariesWatchCmd);\n dictionariesWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add build command to root program as well\n const rootWatchCmd = program\n .command('watch')\n .description(buildOptions.description);\n\n applyOptions(rootWatchCmd, watchOptions.options);\n applyConfigOptions(rootWatchCmd);\n rootWatchCmd.action((options) => {\n watchContentDeclaration({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary pull command\n const pullOptions = {\n description: 'Pull dictionaries from the server',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to pull'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to pull (alias for --dictionaries)',\n ],\n ['--new-dictionaries-path [path]', 'Path to save the new dictionaries'],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--newDictionariesPath [path]',\n '[alias] Path to save the new dictionaries',\n ],\n ],\n };\n\n // Add pull command to dictionaries program\n const dictionariesPullCmd = dictionariesProgram\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(dictionariesPullCmd, pullOptions.options);\n applyConfigOptions(dictionariesPullCmd);\n dictionariesPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: {\n ...options.configOptions,\n baseDir: options.baseDir,\n },\n });\n });\n\n // Add pull command to root program as well\n const rootPullCmd = program\n .command('pull')\n .description(pullOptions.description);\n\n applyOptions(rootPullCmd, pullOptions.options);\n applyConfigOptions(rootPullCmd);\n rootPullCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n pull({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Dictionary push command\n const pushOptions = {\n description:\n 'Push all dictionaries. Create or update the pushed dictionaries',\n options: [\n ['-d, --dictionaries [ids...]', 'List of dictionary IDs to push'],\n [\n '--dictionary [ids...]',\n 'List of dictionary IDs to push (alias for --dictionaries)',\n ],\n [\n '-r, --delete-locale-dictionary',\n 'Delete the local dictionaries after pushing',\n ],\n [\n '-k, --keep-locale-dictionary',\n 'Keep the local dictionaries after pushing',\n ],\n // Backward-compatibility for older tests/flags (camelCase)\n [\n '--deleteLocaleDictionary',\n '[alias] Delete the local dictionaries after pushing',\n ],\n [\n '--keepLocaleDictionary',\n '[alias] Keep the local dictionaries after pushing',\n ],\n [\n '--build [build]',\n 'Build the dictionaries before pushing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build',\n ],\n ],\n };\n\n // Add push command to dictionaries program\n const dictionariesPushCmd = dictionariesProgram\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(dictionariesPushCmd, pushOptions.options);\n applyConfigOptions(dictionariesPushCmd);\n applyGitOptions(dictionariesPushCmd);\n\n dictionariesPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n // Add push command to root program as well\n const rootPushCmd = program\n .command('push')\n .description(pushOptions.description);\n\n applyOptions(rootPushCmd, pushOptions.options);\n applyConfigOptions(rootPushCmd);\n applyGitOptions(rootPushCmd);\n\n rootPushCmd.action((options) => {\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries || []),\n ...(options.dictionary || []),\n ];\n\n return push({\n ...options,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * CONFIGURATION\n */\n\n // Define the parent command\n const configurationProgram = program\n .command('configuration')\n .alias('config')\n .alias('conf')\n .description('Configuration operations');\n\n const configGetCmd = configurationProgram\n .command('get')\n .description('Get the configuration');\n\n applyConfigOptions(configGetCmd);\n configGetCmd.action((options) => {\n getConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Define the `push config` subcommand and add it to the `push` command\n const configPushCmd = configurationProgram\n .command('push')\n .description('Push the configuration');\n\n applyConfigOptions(configPushCmd);\n configPushCmd.action((options) => {\n pushConfig({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n /**\n * PROJECTS\n */\n\n const projectsProgram = program\n .command('projects')\n .alias('project')\n .description('List Intlayer projects');\n\n const projectsListCmd = projectsProgram\n .command('list')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--json', 'Output the results as JSON');\n\n projectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n });\n });\n\n // Add alias for projects list command at root level\n const rootProjectsListCmd = program\n .command('projects-list')\n .alias('pl')\n .description('List all Intlayer projects in the directory')\n .option('--base-dir [baseDir]', 'Base directory to search from')\n .option(\n '--git-root',\n 'Search from the git root directory instead of the base directory'\n )\n .option('--absolute', 'Output the results as absolute paths')\n .option('--json', 'Output the results as JSON');\n\n rootProjectsListCmd.action((options) => {\n listProjectsCommand({\n baseDir: options.baseDir,\n gitRoot: options.gitRoot,\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n /**\n * CONTENT DECLARATION\n */\n\n const contentProgram = program\n .command('content')\n .description('Content declaration operations');\n\n contentProgram\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n // Add alias for content list command\n program\n .command('list')\n .description('List the content declaration files')\n .option('--json', 'Output the results as JSON')\n .option('--absolute', 'Output the results as absolute paths')\n .action((options) => {\n listContentDeclaration({\n json: options.json,\n absolute: options.absolute,\n });\n });\n\n const testProgram = contentProgram\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(testProgram);\n testProgram.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n // Add alias for content test command\n const rootTestCmd = program\n .command('test')\n .description('Test if there are missing translations')\n .option(\n '--build [build]',\n 'Build the dictionaries before testing to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n );\n\n applyConfigOptions(rootTestCmd);\n rootTestCmd.action((options) => {\n testMissingTranslations({\n ...options,\n configOptions: extractConfigOptions(options),\n });\n });\n\n const fillProgram = program\n .command('fill')\n .description('Fill the dictionaries')\n .option('-f, --file [files...]', 'List of Dictionary files to fill')\n .option('--source-locale [sourceLocale]', 'Source locale to translate from')\n .option(\n '--output-locales [outputLocales...]',\n 'Target locales to translate to'\n )\n .option(\n '--mode [mode]',\n 'Fill mode: complete, review. Complete will fill all missing content, review will fill missing content and review existing keys',\n 'complete'\n )\n .option('-k, --keys [keys...]', 'Filter dictionaries based on keys')\n .option(\n '--key [keys...]',\n 'Filter dictionaries based on keys (alias for --keys)'\n )\n .option(\n '--excluded-keys [excludedKeys...]',\n 'Filter out dictionaries based on keys'\n )\n .option(\n '--excluded-key [excludedKeys...]',\n 'Filter out dictionaries based on keys (alias for --excluded-keys)'\n )\n .option(\n '--path-filter [pathFilters...]',\n 'Filter dictionaries based on glob pattern'\n )\n .option(\n '--build [build]',\n 'Build the dictionaries before filling to ensure the content is up to date. True will force the build, false will skip the build, undefined will allow using the cache of the build'\n )\n .option(\n '--skip-metadata',\n 'Skip filling missing metadata (description, title, tags) for dictionaries'\n );\n\n applyConfigOptions(fillProgram);\n applyAIOptions(fillProgram);\n applyGitOptions(fillProgram);\n\n fillProgram.action((options) => {\n // Merge key aliases\n const keys = [...(options.keys ?? []), ...(options.key ?? [])];\n const excludedKeys = [\n ...(options.excludedKeys ?? []),\n ...(options.excludedKey ?? []),\n ];\n // Merge dictionary aliases\n const dictionaries = [\n ...(options.dictionaries ?? []),\n ...(options.dictionary ?? []),\n ];\n\n return fill({\n ...options,\n keys: keys.length > 0 ? keys : undefined,\n excludedKeys: excludedKeys.length > 0 ? excludedKeys : undefined,\n dictionaries: dictionaries.length > 0 ? dictionaries : undefined,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n configOptions: extractConfigOptions(options),\n } as FillOptions);\n });\n\n /**\n * DOCS\n */\n\n const docParams = [\n ['--doc-pattern [docPattern...]', 'Documentation pattern'],\n [\n '--excluded-glob-pattern [excludedGlobPattern...]',\n 'Excluded glob pattern',\n ],\n [\n '--nb-simultaneous-file-processed [nbSimultaneousFileProcessed]',\n 'Number of simultaneous file processed',\n ],\n ['--locales [locales...]', 'Locales'],\n ['--base-locale [baseLocale]', 'Base locale'],\n [\n '--custom-instructions [customInstructions]',\n 'Custom instructions added to the prompt. Usefull to apply specific rules regarding formatting, urls translation, etc.',\n ],\n [\n '--skip-if-modified-before [skipIfModifiedBefore]',\n 'Skip the file if it has been modified before the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n [\n '--skip-if-modified-after [skipIfModifiedAfter]',\n 'Skip the file if it has been modified within the given time. Can be an absolute time as \"2025-12-05\" (string or Date) or a relative time in ms `1 * 60 * 60 * 1000` (1 hour). This option check update time of the file using the `fs.stat` method. So it could be impacted by Git or other tools that modify the file.',\n ],\n ['--skip-if-exists', 'Skip the file if it already exists'],\n ];\n\n const docProgram = program\n .command('doc')\n .description('Documentation operations');\n\n const translateProgram = docProgram\n .command('translate')\n .description('Translate the documentation');\n\n applyConfigOptions(translateProgram);\n applyAIOptions(translateProgram);\n applyGitOptions(translateProgram);\n applyOptions(translateProgram, docParams);\n\n translateProgram.action((options) =>\n translateDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n })\n );\n\n const reviewProgram = docProgram\n .command('review')\n .description('Review the documentation')\n .option(\n '--log',\n 'Log-only mode. Do not translate with AI; instead log the blocks that need attention (with line numbers and content) for the base and target locales, to help another agent generate the translations.'\n );\n\n applyConfigOptions(reviewProgram);\n applyAIOptions(reviewProgram);\n applyGitOptions(reviewProgram);\n applyOptions(reviewProgram, docParams);\n\n reviewProgram.action((options) =>\n reviewDoc({\n docPattern: options.docPattern,\n excludedGlobPattern: options.excludedGlobPattern,\n locales: options.locales,\n baseLocale: options.baseLocale,\n aiOptions: extractAiOptions(options),\n gitOptions: extractGitOptions(options),\n nbSimultaneousFileProcessed: options.nbSimultaneousFileProcessed,\n configOptions: extractConfigOptions(options),\n customInstructions: options.customInstructions,\n skipIfModifiedBefore: options.skipIfModifiedBefore,\n skipIfModifiedAfter: options.skipIfModifiedAfter,\n skipIfExists: options.skipIfExists,\n log: options.log,\n })\n );\n\n const searchProgram = docProgram\n .command('search')\n .description('Search the documentation')\n .argument('<query>', 'Search query')\n .option('--limit [limit]', 'Limit the number of results', '10');\n\n applyConfigOptions(searchProgram);\n\n searchProgram.action((query, options) =>\n searchDoc({\n query,\n limit: options.limit ? parseInt(options.limit, 10) : 10,\n configOptions: extractConfigOptions(options),\n })\n );\n\n /**\n * LIVE SYNC\n */\n\n const liveOptions = [\n ['--with [with...]', 'Start command in parallel with the live sync'],\n ];\n\n const liveCmd = program\n .command('live')\n .description(\n 'Live sync - Watch for changes made on the CMS and update the application content accordingly'\n );\n\n applyOptions(liveCmd, liveOptions);\n applyConfigOptions(liveCmd);\n\n liveCmd.action((options) => liveSync(options));\n\n /**\n * EDITOR\n */\n\n const editorProgram = program\n .command('editor')\n .description('Visual editor operations');\n\n const editorStartCmd = editorProgram\n .command('start')\n .description('Start the Intlayer visual editor');\n\n applyConfigOptions(editorStartCmd);\n\n editorStartCmd.action((options) => {\n startEditor({\n env: options.env,\n envFile: options.envFile,\n });\n });\n\n /**\n * EXTRACT\n */\n const extractProgram = program\n .command('extract')\n .alias('ext')\n .description(\n 'Extract strings from components to be placed in a .content file close to the component'\n );\n\n extractProgram\n .option('-f, --file [files...]', 'List of files to extract')\n .option('--code-only', 'Only extract the component code', false)\n .option('--declaration-only', 'Only generate content declaration', false)\n .action((options) => {\n extract({\n files: options.file,\n configOptions: extractConfigOptions(options),\n codeOnly: options.codeOnly,\n declarationOnly: options.declarationOnly,\n });\n });\n\n /**\n * STANDALONE\n */\n const bundleCmd = program\n .command('standalone')\n .description('Create a standalone bundle of the application content')\n .option(\n '-o, --outfile [outfile]',\n 'Output file for the bundle',\n 'intlayer-bundle.js'\n )\n .option('--packages [packages...]', 'List of packages to bundle')\n .option('--version [version]', 'Version of the packages to bundle')\n .option('--minify', 'Minify the output')\n .option('--platform [platform]', 'Target platform', 'browser')\n .option('--format [format]', 'Output format', 'esm')\n .action((options) => {\n bundle({\n outfile: options.outfile,\n bundlePackages: options.packages,\n version: options.version,\n minify: options.minify,\n platform: options.platform,\n format: options.format,\n configOptions: extractConfigOptions(options),\n });\n });\n\n applyConfigOptions(bundleCmd);\n\n /**\n * SCAN\n */\n const scanCmd = program\n .command('scan')\n .description(\n 'Scan a website to measure its page size and audit its i18n / SEO health'\n )\n .argument('<url>', 'URL of the website to scan')\n .option('--no-deep', 'Disable the deeper puppeteer-based render scan')\n .option('--json', 'Output the results as JSON');\n\n applyConfigOptions(scanCmd);\n\n scanCmd.action((url, options) =>\n scan(url, {\n deep: options.deep,\n json: options.json,\n configOptions: extractConfigOptions(options),\n })\n );\n\n program.parse(process.argv);\n\n /**\n * CI / AUTOMATION\n *\n * Used to iterate over all projects in a monorepo, and help to parse secrets\n */\n program\n .command('ci')\n .description(\n 'Run Intlayer commands with auto-injected credentials from INTLAYER_PROJECT_CREDENTIALS. Detects current project or iterates over all projects.'\n )\n .argument(\n '<command...>',\n 'The intlayer command to execute (e.g., \"fill\", \"push\")'\n )\n .allowUnknownOption() // Allows passing flags like --verbose to the subcommand\n .action((args) => {\n runCI(args);\n });\n\n return program;\n};\n"],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  import { setupAI } from "../utils/setupAI.mjs";
2
2
  import { getOutputFilePath } from "../utils/getOutputFilePath.mjs";
3
3
  import { checkFileModifiedRange } from "../utils/checkFileModifiedRange.mjs";
4
+ import { formatLineRanges } from "../utils/formatLineRanges.mjs";
4
5
  import { reviewFileBlockAware } from "./reviewDocBlockAware.mjs";
6
+ import { logReviewFileBlocks } from "./reviewDocLog.mjs";
5
7
  import { existsSync } from "node:fs";
6
8
  import { join, relative } from "node:path";
7
9
  import { listGitFiles, listGitLines, logConfigDetails } from "@intlayer/chokidar/cli";
@@ -9,6 +11,8 @@ import { formatLocale, formatPath, parallelize } from "@intlayer/chokidar/utils"
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";
14
+ import { readFile } from "node:fs/promises";
15
+ import { buildReviewReport } from "@intlayer/chokidar/docReview";
12
16
  import fg from "fast-glob";
13
17
 
14
18
  //#region src/reviewDoc/reviewDoc.ts
@@ -16,18 +20,26 @@ import fg from "fast-glob";
16
20
  * Main audit function: scans all .md files in "en/" (unless you specified DOC_LIST),
17
21
  * then audits them to each locale in LOCALE_LIST.
18
22
  */
19
- const reviewDoc = async ({ docPattern, locales, excludedGlobPattern, baseLocale, aiOptions, nbSimultaneousFileProcessed, configOptions, customInstructions, skipIfModifiedBefore, skipIfModifiedAfter, skipIfExists, gitOptions }) => {
23
+ const reviewDoc = async ({ docPattern, locales, excludedGlobPattern, baseLocale, aiOptions, nbSimultaneousFileProcessed, configOptions, customInstructions, skipIfModifiedBefore, skipIfModifiedAfter, skipIfExists, gitOptions, log }) => {
20
24
  const configuration = getConfiguration(configOptions);
21
25
  logConfigDetails(configOptions);
22
- const appLogger = getAppLogger(configuration);
23
- const aiResult = await setupAI(configuration, aiOptions);
24
- if (!aiResult?.hasAIAccess) return;
25
- const { aiClient, aiConfig, isCustomAI } = aiResult;
26
- if (isCustomAI && aiClient && aiConfig) {
27
- const { hasAIAccess, error } = await aiClient.checkAISDKAccess(aiConfig);
28
- if (!hasAIAccess) {
29
- appLogger(`${x} ${error}`);
30
- return;
26
+ const appLogger = getAppLogger({ log: {
27
+ ...configuration.log,
28
+ prefix: ""
29
+ } });
30
+ let aiClient;
31
+ let aiConfig;
32
+ if (!log) {
33
+ const aiResult = await setupAI(configuration, aiOptions);
34
+ if (!aiResult?.hasAIAccess) return;
35
+ aiClient = aiResult.aiClient;
36
+ aiConfig = aiResult.aiConfig;
37
+ if (aiResult.isCustomAI && aiClient && aiConfig) {
38
+ const { hasAIAccess, error } = await aiClient.checkAISDKAccess(aiConfig);
39
+ if (!hasAIAccess) {
40
+ appLogger(`${x} ${error}`);
41
+ return;
42
+ }
31
43
  }
32
44
  }
33
45
  if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {
@@ -65,8 +77,23 @@ const reviewDoc = async ({ docPattern, locales, excludedGlobPattern, baseLocale,
65
77
  let changedLines;
66
78
  if (gitOptions) {
67
79
  const gitChangedLines = await listGitLines(absoluteBaseFilePath, gitOptions);
68
- appLogger(`Git changed lines: ${gitChangedLines.join(", ")}`);
69
80
  changedLines = gitChangedLines;
81
+ appLogger(`Changed lines (${formatLocale(baseLocale)}): ${formatLineRanges(gitChangedLines)}`);
82
+ const { blocks } = buildReviewReport({
83
+ baseText: await readFile(absoluteBaseFilePath, "utf-8").catch(() => ""),
84
+ targetText: existsSync(outputFilePath) ? await readFile(outputFilePath, "utf-8").catch(() => "") : "",
85
+ changedLines: gitChangedLines
86
+ });
87
+ const correspondingTargetLines = blocks.flatMap((block) => {
88
+ if (block.action !== "review" || !block.targetLineRange) return [];
89
+ const { start, end } = block.targetLineRange;
90
+ return Array.from({ length: end - start + 1 }, (_unused, offset) => start + offset);
91
+ });
92
+ appLogger(`Corresponding block (${formatLocale(locale)}): ${formatLineRanges(correspondingTargetLines)}`);
93
+ }
94
+ if (log) {
95
+ await logReviewFileBlocks(absoluteBaseFilePath, outputFilePath, locale, baseLocale, configOptions, changedLines);
96
+ return;
70
97
  }
71
98
  await reviewFileBlockAware(absoluteBaseFilePath, outputFilePath, locale, baseLocale, aiOptions, configOptions, customInstructions, changedLines, aiClient, aiConfig);
72
99
  })), (task) => task(), nbSimultaneousFileProcessed ?? 3);
@@ -1 +1 @@
1
- {"version":3,"file":"reviewDoc.mjs","names":[],"sources":["../../../src/reviewDoc/reviewDoc.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type { AIOptions } from '@intlayer/api';\nimport {\n type ListGitFilesOptions,\n listGitFiles,\n listGitLines,\n logConfigDetails,\n} from '@intlayer/chokidar/cli';\nimport {\n formatLocale,\n formatPath,\n parallelize,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n colorizeNumber,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\nimport { checkFileModifiedRange } from '../utils/checkFileModifiedRange';\nimport { getOutputFilePath } from '../utils/getOutputFilePath';\nimport { setupAI } from '../utils/setupAI';\nimport { reviewFileBlockAware } from './reviewDocBlockAware';\n\ntype ReviewDocOptions = {\n docPattern: string[];\n locales: Locale[];\n excludedGlobPattern: string[];\n baseLocale: Locale;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n skipIfExists?: boolean;\n gitOptions?: ListGitFilesOptions;\n};\n\n/**\n * Main audit function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then audits them to each locale in LOCALE_LIST.\n */\nexport const reviewDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n skipIfExists,\n gitOptions,\n}: ReviewDocOptions) => {\n const configuration = getConfiguration(configOptions);\n logConfigDetails(configOptions);\n\n const appLogger = getAppLogger(configuration);\n\n const aiResult = await setupAI(configuration, aiOptions);\n\n if (!aiResult?.hasAIAccess) return;\n\n const { aiClient, aiConfig, isCustomAI } = aiResult;\n\n if (isCustomAI && aiClient && aiConfig) {\n const { hasAIAccess, error } = await aiClient.checkAISDKAccess(aiConfig);\n if (!hasAIAccess) {\n appLogger(`${x} ${error}`);\n return;\n }\n }\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n let docList: string[] = await fg(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n docList = docList.filter((path) =>\n gitChangedFiles.some((gitFile) => join(process.cwd(), path) === gitFile)\n );\n }\n }\n\n // OAuth handled by API proxy internally\n\n appLogger(`Base locale is ${formatLocale(baseLocale)}`);\n appLogger(\n `Reviewing ${colorizeNumber(locales.length)} locales: [ ${formatLocale(locales)} ]`\n );\n\n appLogger(`Reviewing ${colorizeNumber(docList.length)} files:`);\n appLogger(docList.map((path) => ` - ${formatPath(path)}\\n`));\n\n // Create all tasks to be processed\n const allTasks = docList.flatMap((docPath) =>\n locales.map((locale) => async () => {\n appLogger(\n `Reviewing file: ${formatPath(docPath)} to ${formatLocale(locale)}`\n );\n\n const absoluteBaseFilePath = join(configuration.system.baseDir, docPath);\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n // Skip if file exists and skipIfExists option is enabled\n if (skipIfExists && existsSync(outputFilePath)) {\n const relativePath = relative(\n configuration.system.baseDir,\n outputFilePath\n );\n appLogger(\n `${colorize('⊘', ANSIColors.YELLOW)} File ${formatPath(relativePath)} already exists, skipping.`\n );\n return;\n }\n\n // Check modification range only if the file exists\n if (existsSync(outputFilePath)) {\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n } else if (skipIfModifiedBefore || skipIfModifiedAfter) {\n // Log if we intended to check modification time but couldn't because the file doesn't exist\n appLogger(\n `${colorize('!', ANSIColors.YELLOW)} File ${formatPath(outputFilePath)} does not exist, skipping modification date check.`\n );\n }\n\n let changedLines: number[] | undefined;\n // FIXED: Enable git optimization that was previously commented out\n if (gitOptions) {\n const gitChangedLines = await listGitLines(\n absoluteBaseFilePath,\n gitOptions\n );\n\n appLogger(`Git changed lines: ${gitChangedLines.join(', ')}`);\n changedLines = gitChangedLines;\n }\n\n await reviewFileBlockAware(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locale,\n baseLocale,\n aiOptions,\n configOptions,\n customInstructions,\n changedLines,\n aiClient,\n aiConfig\n );\n })\n );\n\n await parallelize(\n allTasks,\n (task) => task(),\n nbSimultaneousFileProcessed ?? 3\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmDA,MAAa,YAAY,OAAO,EAC9B,YACA,SACA,qBACA,YACA,WACA,6BACA,eACA,oBACA,sBACA,qBACA,cACA,iBACsB;CACtB,MAAM,gBAAgB,iBAAiB,cAAc;AACrD,kBAAiB,cAAc;CAE/B,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,WAAW,MAAM,QAAQ,eAAe,UAAU;AAExD,KAAI,CAAC,UAAU,YAAa;CAE5B,MAAM,EAAE,UAAU,UAAU,eAAe;AAE3C,KAAI,cAAc,YAAY,UAAU;EACtC,MAAM,EAAE,aAAa,UAAU,MAAM,SAAS,iBAAiB,SAAS;AACxE,MAAI,CAAC,aAAa;AAChB,aAAU,GAAG,EAAE,GAAG,QAAQ;AAC1B;;;AAIJ,KAAI,+BAA+B,8BAA8B,IAAI;AACnE,YACE,kDAAkD,4BAA4B,+CAC/E;AACD,gCAA8B;;CAGhC,IAAI,UAAoB,MAAM,GAAG,YAAY,EAC3C,QAAQ,qBACT,CAAC;AAEF,KAAI,YAAY;EACd,MAAM,kBAAkB,MAAM,aAAa,WAAW;AAEtD,MAAI,gBAIF,WAAU,QAAQ,QAAQ,SACxB,gBAAgB,MAAM,YAAY,KAAK,QAAQ,KAAK,EAAE,KAAK,KAAK,QAAQ,CACzE;;AAML,WAAU,kBAAkB,aAAa,WAAW,GAAG;AACvD,WACE,aAAa,eAAe,QAAQ,OAAO,CAAC,cAAc,aAAa,QAAQ,CAAC,IACjF;AAED,WAAU,aAAa,eAAe,QAAQ,OAAO,CAAC,SAAS;AAC/D,WAAU,QAAQ,KAAK,SAAS,MAAM,WAAW,KAAK,CAAC,IAAI,CAAC;AAyE5D,OAAM,YAtEW,QAAQ,SAAS,YAChC,QAAQ,KAAK,WAAW,YAAY;AAClC,YACE,mBAAmB,WAAW,QAAQ,CAAC,MAAM,aAAa,OAAO,GAClE;EAED,MAAM,uBAAuB,KAAK,cAAc,OAAO,SAAS,QAAQ;EACxE,MAAM,iBAAiB,kBACrB,sBACA,QACA,WACD;AAGD,MAAI,gBAAgB,WAAW,eAAe,EAAE;GAC9C,MAAM,eAAe,SACnB,cAAc,OAAO,SACrB,eACD;AACD,aACE,GAAG,SAAS,KAAK,WAAW,OAAO,CAAC,QAAQ,WAAW,aAAa,CAAC,4BACtE;AACD;;AAIF,MAAI,WAAW,eAAe,EAAE;GAC9B,MAAM,uBAAuB,uBAAuB,gBAAgB;IAClE;IACA;IACD,CAAC;AAEF,OAAI,qBAAqB,WAAW;AAClC,cAAU,qBAAqB,QAAQ;AACvC;;aAEO,wBAAwB,oBAEjC,WACE,GAAG,SAAS,KAAK,WAAW,OAAO,CAAC,QAAQ,WAAW,eAAe,CAAC,oDACxE;EAGH,IAAI;AAEJ,MAAI,YAAY;GACd,MAAM,kBAAkB,MAAM,aAC5B,sBACA,WACD;AAED,aAAU,sBAAsB,gBAAgB,KAAK,KAAK,GAAG;AAC7D,kBAAe;;AAGjB,QAAM,qBACJ,sBACA,gBACA,QACA,YACA,WACA,eACA,oBACA,cACA,UACA,SACD;GACD,CAIM,GACP,SAAS,MAAM,EAChB,+BAA+B,EAChC"}
1
+ {"version":3,"file":"reviewDoc.mjs","names":[],"sources":["../../../src/reviewDoc/reviewDoc.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { AIConfig } from '@intlayer/ai';\nimport type { AIOptions } from '@intlayer/api';\nimport {\n type ListGitFilesOptions,\n listGitFiles,\n listGitLines,\n logConfigDetails,\n} from '@intlayer/chokidar/cli';\nimport { buildReviewReport } from '@intlayer/chokidar/docReview';\nimport {\n formatLocale,\n formatPath,\n parallelize,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n colorizeNumber,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\nimport { checkFileModifiedRange } from '../utils/checkFileModifiedRange';\nimport { formatLineRanges } from '../utils/formatLineRanges';\nimport { getOutputFilePath } from '../utils/getOutputFilePath';\nimport { type AIClient, setupAI } from '../utils/setupAI';\nimport { reviewFileBlockAware } from './reviewDocBlockAware';\nimport { logReviewFileBlocks } from './reviewDocLog';\n\ntype ReviewDocOptions = {\n docPattern: string[];\n locales: Locale[];\n excludedGlobPattern: string[];\n baseLocale: Locale;\n aiOptions?: AIOptions;\n nbSimultaneousFileProcessed?: number;\n configOptions?: GetConfigurationOptions;\n customInstructions?: string;\n skipIfModifiedBefore?: number | string | Date;\n skipIfModifiedAfter?: number | string | Date;\n skipIfExists?: boolean;\n gitOptions?: ListGitFilesOptions;\n /**\n * Log-only mode. Instead of translating the changed blocks with AI, log the\n * blocks that need attention (with line numbers and content) for the base and\n * target locales, so another agent can generate the translations.\n */\n log?: boolean;\n};\n\n/**\n * Main audit function: scans all .md files in \"en/\" (unless you specified DOC_LIST),\n * then audits them to each locale in LOCALE_LIST.\n */\nexport const reviewDoc = async ({\n docPattern,\n locales,\n excludedGlobPattern,\n baseLocale,\n aiOptions,\n nbSimultaneousFileProcessed,\n configOptions,\n customInstructions,\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n skipIfExists,\n gitOptions,\n log,\n}: ReviewDocOptions) => {\n const configuration = getConfiguration(configOptions);\n logConfigDetails(configOptions);\n\n const appLogger = getAppLogger({ log: { ...configuration.log, prefix: '' } });\n\n // Log-only mode does not call any AI, so the AI access checks are skipped.\n let aiClient: AIClient | undefined;\n let aiConfig: AIConfig | undefined;\n\n if (!log) {\n const aiResult = await setupAI(configuration, aiOptions);\n\n if (!aiResult?.hasAIAccess) return;\n\n aiClient = aiResult.aiClient;\n aiConfig = aiResult.aiConfig;\n\n if (aiResult.isCustomAI && aiClient && aiConfig) {\n const { hasAIAccess, error } = await aiClient.checkAISDKAccess(aiConfig);\n if (!hasAIAccess) {\n appLogger(`${x} ${error}`);\n return;\n }\n }\n }\n\n if (nbSimultaneousFileProcessed && nbSimultaneousFileProcessed > 10) {\n appLogger(\n `Warning: nbSimultaneousFileProcessed is set to ${nbSimultaneousFileProcessed}, which is greater than 10. Setting it to 10.`\n );\n nbSimultaneousFileProcessed = 10; // Limit the number of simultaneous file processed to 10\n }\n\n let docList: string[] = await fg(docPattern, {\n ignore: excludedGlobPattern,\n });\n\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n docList = docList.filter((path) =>\n gitChangedFiles.some((gitFile) => join(process.cwd(), path) === gitFile)\n );\n }\n }\n\n // OAuth handled by API proxy internally\n\n appLogger(`Base locale is ${formatLocale(baseLocale)}`);\n appLogger(\n `Reviewing ${colorizeNumber(locales.length)} locales: [ ${formatLocale(locales)} ]`\n );\n\n appLogger(`Reviewing ${colorizeNumber(docList.length)} files:`);\n appLogger(docList.map((path) => ` - ${formatPath(path)}\\n`));\n\n // Create all tasks to be processed\n const allTasks = docList.flatMap((docPath) =>\n locales.map((locale) => async () => {\n appLogger(\n `Reviewing file: ${formatPath(docPath)} to ${formatLocale(locale)}`\n );\n\n const absoluteBaseFilePath = join(configuration.system.baseDir, docPath);\n const outputFilePath = getOutputFilePath(\n absoluteBaseFilePath,\n locale,\n baseLocale\n );\n\n // Skip if file exists and skipIfExists option is enabled\n if (skipIfExists && existsSync(outputFilePath)) {\n const relativePath = relative(\n configuration.system.baseDir,\n outputFilePath\n );\n appLogger(\n `${colorize('⊘', ANSIColors.YELLOW)} File ${formatPath(relativePath)} already exists, skipping.`\n );\n return;\n }\n\n // Check modification range only if the file exists\n if (existsSync(outputFilePath)) {\n const fileModificationData = checkFileModifiedRange(outputFilePath, {\n skipIfModifiedBefore,\n skipIfModifiedAfter,\n });\n\n if (fileModificationData.isSkipped) {\n appLogger(fileModificationData.message);\n return;\n }\n } else if (skipIfModifiedBefore || skipIfModifiedAfter) {\n // Log if we intended to check modification time but couldn't because the file doesn't exist\n appLogger(\n `${colorize('!', ANSIColors.YELLOW)} File ${formatPath(outputFilePath)} does not exist, skipping modification date check.`\n );\n }\n\n let changedLines: number[] | undefined;\n // FIXED: Enable git optimization that was previously commented out\n if (gitOptions) {\n const gitChangedLines = await listGitLines(\n absoluteBaseFilePath,\n gitOptions\n );\n changedLines = gitChangedLines;\n\n // Report the base lines that changed, then the corresponding line span\n // in the target document — i.e. the blocks the alignment will actually\n // re-translate. `review` blocks are exactly the aligned base blocks the\n // changed lines touched, so their `targetLineRange` is the matching span\n // in the existing translation.\n appLogger(\n `Changed lines (${formatLocale(baseLocale)}): ${formatLineRanges(gitChangedLines)}`\n );\n\n const baseText = await readFile(absoluteBaseFilePath, 'utf-8').catch(\n () => ''\n );\n const targetText = existsSync(outputFilePath)\n ? await readFile(outputFilePath, 'utf-8').catch(() => '')\n : '';\n\n const { blocks } = buildReviewReport({\n baseText,\n targetText,\n changedLines: gitChangedLines,\n });\n\n const correspondingTargetLines = blocks.flatMap((block) => {\n if (block.action !== 'review' || !block.targetLineRange) return [];\n\n const { start, end } = block.targetLineRange;\n return Array.from(\n { length: end - start + 1 },\n (_unused, offset) => start + offset\n );\n });\n\n appLogger(\n `Corresponding block (${formatLocale(locale)}): ${formatLineRanges(correspondingTargetLines)}`\n );\n }\n\n if (log) {\n await logReviewFileBlocks(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locale,\n baseLocale,\n configOptions,\n changedLines\n );\n return;\n }\n\n await reviewFileBlockAware(\n absoluteBaseFilePath,\n outputFilePath,\n locale as Locale,\n baseLocale,\n aiOptions,\n configOptions,\n customInstructions,\n changedLines,\n aiClient,\n aiConfig\n );\n })\n );\n\n await parallelize(\n allTasks,\n (task) => task(),\n nbSimultaneousFileProcessed ?? 3\n );\n};\n"],"mappings":"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"}