@intlayer/cli 7.5.10 → 7.5.12

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 (107) hide show
  1. package/dist/cjs/ci.cjs +73 -0
  2. package/dist/cjs/ci.cjs.map +1 -0
  3. package/dist/cjs/cli.cjs +41 -6
  4. package/dist/cjs/cli.cjs.map +1 -1
  5. package/dist/cjs/editor.cjs +1 -1
  6. package/dist/cjs/index.cjs +4 -5
  7. package/dist/cjs/listContentDeclaration.cjs +6 -2
  8. package/dist/cjs/listContentDeclaration.cjs.map +1 -1
  9. package/dist/cjs/listProjects.cjs +28 -0
  10. package/dist/cjs/listProjects.cjs.map +1 -0
  11. package/dist/cjs/{reviewDoc.cjs → reviewDoc/reviewDoc.cjs} +17 -15
  12. package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -0
  13. package/dist/cjs/{reviewDocBlockAware.cjs → reviewDoc/reviewDocBlockAware.cjs} +12 -8
  14. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -0
  15. package/dist/cjs/translateDoc/index.cjs +8 -0
  16. package/dist/cjs/translateDoc/translateDoc.cjs +74 -0
  17. package/dist/cjs/translateDoc/translateDoc.cjs.map +1 -0
  18. package/dist/cjs/translateDoc/translateFile.cjs +103 -0
  19. package/dist/cjs/translateDoc/translateFile.cjs.map +1 -0
  20. package/dist/cjs/translateDoc/types.cjs +0 -0
  21. package/dist/cjs/translateDoc/validation.cjs +49 -0
  22. package/dist/cjs/translateDoc/validation.cjs.map +1 -0
  23. package/dist/cjs/translation-alignment/planActions.cjs +2 -4
  24. package/dist/cjs/translation-alignment/planActions.cjs.map +1 -1
  25. package/dist/cjs/translation-alignment/segmentDocument.cjs +35 -101
  26. package/dist/cjs/translation-alignment/segmentDocument.cjs.map +1 -1
  27. package/dist/cjs/utils/checkAccess.cjs +2 -1
  28. package/dist/cjs/utils/checkAccess.cjs.map +1 -1
  29. package/dist/cjs/utils/setupAI.cjs +20 -11
  30. package/dist/cjs/utils/setupAI.cjs.map +1 -1
  31. package/dist/esm/auth/login.mjs +16 -16
  32. package/dist/esm/auth/login.mjs.map +1 -1
  33. package/dist/esm/ci.mjs +72 -0
  34. package/dist/esm/ci.mjs.map +1 -0
  35. package/dist/esm/cli.mjs +39 -4
  36. package/dist/esm/cli.mjs.map +1 -1
  37. package/dist/esm/editor.mjs +1 -1
  38. package/dist/esm/index.mjs +3 -3
  39. package/dist/esm/listContentDeclaration.mjs +6 -2
  40. package/dist/esm/listContentDeclaration.mjs.map +1 -1
  41. package/dist/esm/listProjects.mjs +27 -0
  42. package/dist/esm/listProjects.mjs.map +1 -0
  43. package/dist/esm/pull.mjs +6 -6
  44. package/dist/esm/pull.mjs.map +1 -1
  45. package/dist/esm/push/push.mjs +7 -7
  46. package/dist/esm/push/push.mjs.map +1 -1
  47. package/dist/esm/{reviewDoc.mjs → reviewDoc/reviewDoc.mjs} +14 -12
  48. package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -0
  49. package/dist/esm/{reviewDocBlockAware.mjs → reviewDoc/reviewDocBlockAware.mjs} +11 -7
  50. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -0
  51. package/dist/esm/translateDoc/index.mjs +5 -0
  52. package/dist/esm/translateDoc/translateDoc.mjs +72 -0
  53. package/dist/esm/translateDoc/translateDoc.mjs.map +1 -0
  54. package/dist/esm/translateDoc/translateFile.mjs +102 -0
  55. package/dist/esm/translateDoc/translateFile.mjs.map +1 -0
  56. package/dist/esm/translateDoc/types.mjs +0 -0
  57. package/dist/esm/translateDoc/validation.mjs +47 -0
  58. package/dist/esm/translateDoc/validation.mjs.map +1 -0
  59. package/dist/esm/translation-alignment/planActions.mjs +2 -4
  60. package/dist/esm/translation-alignment/planActions.mjs.map +1 -1
  61. package/dist/esm/translation-alignment/segmentDocument.mjs +35 -101
  62. package/dist/esm/translation-alignment/segmentDocument.mjs.map +1 -1
  63. package/dist/esm/utils/checkAccess.mjs +2 -1
  64. package/dist/esm/utils/checkAccess.mjs.map +1 -1
  65. package/dist/esm/utils/setupAI.mjs +20 -11
  66. package/dist/esm/utils/setupAI.mjs.map +1 -1
  67. package/dist/types/ci.d.ts +5 -0
  68. package/dist/types/ci.d.ts.map +1 -0
  69. package/dist/types/cli.d.ts.map +1 -1
  70. package/dist/types/index.d.ts +3 -3
  71. package/dist/types/listContentDeclaration.d.ts +2 -0
  72. package/dist/types/listContentDeclaration.d.ts.map +1 -1
  73. package/dist/types/listProjects.d.ts +11 -0
  74. package/dist/types/listProjects.d.ts.map +1 -0
  75. package/dist/types/pull.d.ts.map +1 -1
  76. package/dist/types/pushConfig.d.ts.map +1 -1
  77. package/dist/types/{reviewDoc.d.ts → reviewDoc/reviewDoc.d.ts} +1 -1
  78. package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -0
  79. package/dist/types/{reviewDocBlockAware.d.ts → reviewDoc/reviewDocBlockAware.d.ts} +2 -2
  80. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -0
  81. package/dist/types/translateDoc/index.d.ts +5 -0
  82. package/dist/types/translateDoc/translateDoc.d.ts +21 -0
  83. package/dist/types/translateDoc/translateDoc.d.ts.map +1 -0
  84. package/dist/types/translateDoc/translateFile.d.ts +21 -0
  85. package/dist/types/translateDoc/translateFile.d.ts.map +1 -0
  86. package/dist/types/translateDoc/types.d.ts +47 -0
  87. package/dist/types/translateDoc/types.d.ts.map +1 -0
  88. package/dist/types/translateDoc/validation.d.ts +16 -0
  89. package/dist/types/translateDoc/validation.d.ts.map +1 -0
  90. package/dist/types/translation-alignment/planActions.d.ts +2 -2
  91. package/dist/types/translation-alignment/planActions.d.ts.map +1 -1
  92. package/dist/types/translation-alignment/rebuildDocument.d.ts.map +1 -1
  93. package/dist/types/translation-alignment/segmentDocument.d.ts.map +1 -1
  94. package/dist/types/utils/setupAI.d.ts.map +1 -1
  95. package/package.json +11 -10
  96. package/dist/cjs/reviewDoc.cjs.map +0 -1
  97. package/dist/cjs/reviewDocBlockAware.cjs.map +0 -1
  98. package/dist/cjs/translateDoc.cjs +0 -132
  99. package/dist/cjs/translateDoc.cjs.map +0 -1
  100. package/dist/esm/reviewDoc.mjs.map +0 -1
  101. package/dist/esm/reviewDocBlockAware.mjs.map +0 -1
  102. package/dist/esm/translateDoc.mjs +0 -129
  103. package/dist/esm/translateDoc.mjs.map +0 -1
  104. package/dist/types/reviewDoc.d.ts.map +0 -1
  105. package/dist/types/reviewDocBlockAware.d.ts.map +0 -1
  106. package/dist/types/translateDoc.d.ts +0 -47
  107. package/dist/types/translateDoc.d.ts.map +0 -1
@@ -0,0 +1,47 @@
1
+ //#region src/translateDoc/validation.ts
2
+ /**
3
+ * Validates that the translated content matches the structure of the original.
4
+ * Throws an error if a mismatch is found, triggering a retry.
5
+ */
6
+ const validateTranslation = (original, translated, logger) => {
7
+ const errors = [];
8
+ if (original.trimStart().startsWith("---")) {
9
+ if (!translated.trimStart().startsWith("---")) errors.push("YAML Frontmatter missing: Input starts with \"---\", output does not.");
10
+ const originalDashes = (original.match(/^---$/gm) || []).length;
11
+ const translatedDashes = (translated.match(/^---$/gm) || []).length;
12
+ if (originalDashes >= 2 && translatedDashes < 2) errors.push("YAML Frontmatter unclosed: Input has closing \"---\", output is missing it.");
13
+ }
14
+ const fenceRegex = /^\s*```/gm;
15
+ const originalFences = (original.match(fenceRegex) || []).length;
16
+ const translatedFences = (translated.match(fenceRegex) || []).length;
17
+ if (originalFences !== translatedFences) errors.push(`Code fence mismatch: Input has ${originalFences}, output has ${translatedFences}`);
18
+ const ratio = translated.length / (original.length || 1);
19
+ const isTooLong = ratio > 2.5;
20
+ const isSignificantLength = original.length > 50;
21
+ if (isTooLong && isSignificantLength) errors.push(`Length deviation: Output is ${translated.length} chars vs Input ${original.length} (${ratio.toFixed(1)}x). Likely included context.`);
22
+ const originalLines = original.split("\n").length;
23
+ const translatedLines = translated.split("\n").length;
24
+ if (originalLines > 5) {
25
+ if (translatedLines < originalLines * .4) errors.push(`Line count deviation: Output has ${translatedLines} lines, Input has ${originalLines}. Likely content deletion.`);
26
+ }
27
+ if (errors.length > 0) {
28
+ logger(`Validation Failed: ${errors.join(", ")}`);
29
+ return false;
30
+ }
31
+ return true;
32
+ };
33
+ /**
34
+ * Clean common AI artifacts
35
+ */
36
+ const sanitizeChunk = (translated, original) => {
37
+ let cleaned = translated;
38
+ const match = cleaned.match(/^```(?:markdown|md|txt)?\n([\s\S]*?)\n```$/i);
39
+ if (match) cleaned = match[1];
40
+ if (!original.startsWith("\n") && cleaned.startsWith("\n")) cleaned = cleaned.replace(/^\n+/, "");
41
+ if (!original.startsWith(" ") && cleaned.startsWith(" ")) cleaned = cleaned.trimStart();
42
+ return cleaned;
43
+ };
44
+
45
+ //#endregion
46
+ export { sanitizeChunk, validateTranslation };
47
+ //# sourceMappingURL=validation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.mjs","names":["errors: string[]"],"sources":["../../../src/translateDoc/validation.ts"],"sourcesContent":["import type { Logger } from '@intlayer/config';\n\n/**\n * Validates that the translated content matches the structure of the original.\n * Throws an error if a mismatch is found, triggering a retry.\n */\nexport const validateTranslation = (\n original: string,\n translated: string,\n logger: Logger\n): boolean => {\n const errors: string[] = [];\n\n // YAML Frontmatter Integrity (CRITICAL)\n if (original.trimStart().startsWith('---')) {\n if (!translated.trimStart().startsWith('---')) {\n errors.push(\n 'YAML Frontmatter missing: Input starts with \"---\", output does not.'\n );\n }\n const originalDashes = (original.match(/^---$/gm) || []).length;\n const translatedDashes = (translated.match(/^---$/gm) || []).length;\n if (originalDashes >= 2 && translatedDashes < 2) {\n errors.push(\n 'YAML Frontmatter unclosed: Input has closing \"---\", output is missing it.'\n );\n }\n }\n\n // Code Fence Check\n const fenceRegex = /^\\s*```/gm;\n const originalFences = (original.match(fenceRegex) || []).length;\n const translatedFences = (translated.match(fenceRegex) || []).length;\n\n if (originalFences !== translatedFences) {\n errors.push(\n `Code fence mismatch: Input has ${originalFences}, output has ${translatedFences}`\n );\n }\n\n // Length/Duplication Check\n const ratio = translated.length / (original.length || 1);\n const isTooLong = ratio > 2.5;\n const isSignificantLength = original.length > 50;\n\n if (isTooLong && isSignificantLength) {\n errors.push(\n `Length deviation: Output is ${translated.length} chars vs Input ${original.length} (${ratio.toFixed(1)}x). Likely included context.`\n );\n }\n\n // Line Count Heuristic\n const originalLines = original.split('\\n').length;\n const translatedLines = translated.split('\\n').length;\n\n if (originalLines > 5) {\n if (translatedLines < originalLines * 0.4) {\n errors.push(\n `Line count deviation: Output has ${translatedLines} lines, Input has ${originalLines}. Likely content deletion.`\n );\n }\n }\n\n if (errors.length > 0) {\n logger(`Validation Failed: ${errors.join(', ')}`);\n return false;\n }\n\n return true;\n};\n\n/**\n * Clean common AI artifacts\n */\nexport const sanitizeChunk = (translated: string, original: string): string => {\n let cleaned = translated;\n const wrapRegex = /^```(?:markdown|md|txt)?\\n([\\s\\S]*?)\\n```$/i;\n const match = cleaned.match(wrapRegex);\n if (match) cleaned = match[1];\n\n if (!original.startsWith('\\n') && cleaned.startsWith('\\n')) {\n cleaned = cleaned.replace(/^\\n+/, '');\n }\n if (!original.startsWith(' ') && cleaned.startsWith(' ')) {\n cleaned = cleaned.trimStart();\n }\n return cleaned;\n};\n"],"mappings":";;;;;AAMA,MAAa,uBACX,UACA,YACA,WACY;CACZ,MAAMA,SAAmB,EAAE;AAG3B,KAAI,SAAS,WAAW,CAAC,WAAW,MAAM,EAAE;AAC1C,MAAI,CAAC,WAAW,WAAW,CAAC,WAAW,MAAM,CAC3C,QAAO,KACL,wEACD;EAEH,MAAM,kBAAkB,SAAS,MAAM,UAAU,IAAI,EAAE,EAAE;EACzD,MAAM,oBAAoB,WAAW,MAAM,UAAU,IAAI,EAAE,EAAE;AAC7D,MAAI,kBAAkB,KAAK,mBAAmB,EAC5C,QAAO,KACL,8EACD;;CAKL,MAAM,aAAa;CACnB,MAAM,kBAAkB,SAAS,MAAM,WAAW,IAAI,EAAE,EAAE;CAC1D,MAAM,oBAAoB,WAAW,MAAM,WAAW,IAAI,EAAE,EAAE;AAE9D,KAAI,mBAAmB,iBACrB,QAAO,KACL,kCAAkC,eAAe,eAAe,mBACjE;CAIH,MAAM,QAAQ,WAAW,UAAU,SAAS,UAAU;CACtD,MAAM,YAAY,QAAQ;CAC1B,MAAM,sBAAsB,SAAS,SAAS;AAE9C,KAAI,aAAa,oBACf,QAAO,KACL,+BAA+B,WAAW,OAAO,kBAAkB,SAAS,OAAO,IAAI,MAAM,QAAQ,EAAE,CAAC,8BACzG;CAIH,MAAM,gBAAgB,SAAS,MAAM,KAAK,CAAC;CAC3C,MAAM,kBAAkB,WAAW,MAAM,KAAK,CAAC;AAE/C,KAAI,gBAAgB,GAClB;MAAI,kBAAkB,gBAAgB,GACpC,QAAO,KACL,oCAAoC,gBAAgB,oBAAoB,cAAc,4BACvF;;AAIL,KAAI,OAAO,SAAS,GAAG;AACrB,SAAO,sBAAsB,OAAO,KAAK,KAAK,GAAG;AACjD,SAAO;;AAGT,QAAO;;;;;AAMT,MAAa,iBAAiB,YAAoB,aAA6B;CAC7E,IAAI,UAAU;CAEd,MAAM,QAAQ,QAAQ,MADJ,8CACoB;AACtC,KAAI,MAAO,WAAU,MAAM;AAE3B,KAAI,CAAC,SAAS,WAAW,KAAK,IAAI,QAAQ,WAAW,KAAK,CACxD,WAAU,QAAQ,QAAQ,QAAQ,GAAG;AAEvC,KAAI,CAAC,SAAS,WAAW,IAAI,IAAI,QAAQ,WAAW,IAAI,CACtD,WAAU,QAAQ,WAAW;AAE/B,QAAO"}
@@ -1,5 +1,5 @@
1
1
  //#region src/translation-alignment/planActions.ts
2
- const planAlignmentActions = (alignment, changedEnglishBlockIndexes, similarityOptions) => {
2
+ const planAlignmentActions = (alignment, changedEnglishBlockIndexes) => {
3
3
  const actions = [];
4
4
  const seenFrench = /* @__PURE__ */ new Set();
5
5
  alignment.forEach((pair) => {
@@ -23,9 +23,7 @@ const planAlignmentActions = (alignment, changedEnglishBlockIndexes, similarityO
23
23
  return;
24
24
  }
25
25
  if (englishIndex >= 0 && frenchIndex !== null) {
26
- const isChanged = changedEnglishBlockIndexes.has(englishIndex);
27
- const isHighSimilarity = pair.similarityScore >= similarityOptions.minimumMatchForReuse;
28
- if (!isChanged && isHighSimilarity) actions.push({
26
+ if (!changedEnglishBlockIndexes.has(englishIndex)) actions.push({
29
27
  kind: "reuse",
30
28
  englishIndex,
31
29
  frenchIndex
@@ -1 +1 @@
1
- {"version":3,"file":"planActions.mjs","names":["actions: PlannedAction[]"],"sources":["../../../src/translation-alignment/planActions.ts"],"sourcesContent":["import type {\n AlignmentPair,\n AlignmentPlan,\n PlannedAction,\n SimilarityOptions,\n} from './types';\n\nexport const planAlignmentActions = (\n alignment: AlignmentPair[],\n changedEnglishBlockIndexes: Set<number>,\n similarityOptions: SimilarityOptions\n): AlignmentPlan => {\n const actions: PlannedAction[] = [];\n const seenFrench = new Set<number>();\n\n alignment.forEach((pair) => {\n const englishIndex = pair.englishIndex;\n const frenchIndex = pair.frenchIndex;\n\n if (englishIndex === -1 && frenchIndex !== null) {\n // french only -> delete\n if (!seenFrench.has(frenchIndex)) {\n actions.push({ kind: 'delete', frenchIndex });\n seenFrench.add(frenchIndex);\n }\n return;\n }\n\n if (englishIndex >= 0 && frenchIndex === null) {\n // new english block\n actions.push({ kind: 'insert_new', englishIndex });\n return;\n }\n\n if (englishIndex >= 0 && frenchIndex !== null) {\n // matched pair\n const isChanged = changedEnglishBlockIndexes.has(englishIndex);\n const isHighSimilarity =\n pair.similarityScore >= similarityOptions.minimumMatchForReuse;\n\n if (!isChanged && isHighSimilarity) {\n actions.push({ kind: 'reuse', englishIndex, frenchIndex });\n } else {\n actions.push({ kind: 'review', englishIndex, frenchIndex });\n }\n seenFrench.add(frenchIndex);\n return;\n }\n });\n\n return { actions };\n};\n"],"mappings":";AAOA,MAAa,wBACX,WACA,4BACA,sBACkB;CAClB,MAAMA,UAA2B,EAAE;CACnC,MAAM,6BAAa,IAAI,KAAa;AAEpC,WAAU,SAAS,SAAS;EAC1B,MAAM,eAAe,KAAK;EAC1B,MAAM,cAAc,KAAK;AAEzB,MAAI,iBAAiB,MAAM,gBAAgB,MAAM;AAE/C,OAAI,CAAC,WAAW,IAAI,YAAY,EAAE;AAChC,YAAQ,KAAK;KAAE,MAAM;KAAU;KAAa,CAAC;AAC7C,eAAW,IAAI,YAAY;;AAE7B;;AAGF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAE7C,WAAQ,KAAK;IAAE,MAAM;IAAc;IAAc,CAAC;AAClD;;AAGF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;GAE7C,MAAM,YAAY,2BAA2B,IAAI,aAAa;GAC9D,MAAM,mBACJ,KAAK,mBAAmB,kBAAkB;AAE5C,OAAI,CAAC,aAAa,iBAChB,SAAQ,KAAK;IAAE,MAAM;IAAS;IAAc;IAAa,CAAC;OAE1D,SAAQ,KAAK;IAAE,MAAM;IAAU;IAAc;IAAa,CAAC;AAE7D,cAAW,IAAI,YAAY;AAC3B;;GAEF;AAEF,QAAO,EAAE,SAAS"}
1
+ {"version":3,"file":"planActions.mjs","names":["actions: PlannedAction[]"],"sources":["../../../src/translation-alignment/planActions.ts"],"sourcesContent":["import type { AlignmentPair, AlignmentPlan, PlannedAction } from './types';\n\nexport const planAlignmentActions = (\n alignment: AlignmentPair[],\n changedEnglishBlockIndexes: Set<number>\n): AlignmentPlan => {\n const actions: PlannedAction[] = [];\n const seenFrench = new Set<number>();\n\n alignment.forEach((pair) => {\n const englishIndex = pair.englishIndex;\n const frenchIndex = pair.frenchIndex;\n\n // Case 1: Deletion (Exists in FR, not in EN)\n if (englishIndex === -1 && frenchIndex !== null) {\n if (!seenFrench.has(frenchIndex)) {\n actions.push({ kind: 'delete', frenchIndex });\n seenFrench.add(frenchIndex);\n }\n return;\n }\n\n // Case 2: New Insertion (Exists in EN, not in FR)\n if (englishIndex >= 0 && frenchIndex === null) {\n actions.push({ kind: 'insert_new', englishIndex });\n return;\n }\n\n // Case 3: Alignment (Exists in both)\n if (englishIndex >= 0 && frenchIndex !== null) {\n const isChanged = changedEnglishBlockIndexes.has(englishIndex);\n\n // If the block is NOT marked as changed by Git, we REUSE it.\n // We assume the existing translation is correct because the source hasn't been touched.\n // We ignore 'similarityScore' here because EN vs UK text will always have low similarity.\n if (!isChanged) {\n actions.push({ kind: 'reuse', englishIndex, frenchIndex });\n } else {\n // If the block IS changed, we normally Review.\n // OPTIONAL: You could add a check here for 'similarityScore > 0.99'\n // to detect whitespace-only changes, but generally, if Git says changed, we Review.\n actions.push({ kind: 'review', englishIndex, frenchIndex });\n }\n\n seenFrench.add(frenchIndex);\n return;\n }\n });\n\n return { actions };\n};\n"],"mappings":";AAEA,MAAa,wBACX,WACA,+BACkB;CAClB,MAAMA,UAA2B,EAAE;CACnC,MAAM,6BAAa,IAAI,KAAa;AAEpC,WAAU,SAAS,SAAS;EAC1B,MAAM,eAAe,KAAK;EAC1B,MAAM,cAAc,KAAK;AAGzB,MAAI,iBAAiB,MAAM,gBAAgB,MAAM;AAC/C,OAAI,CAAC,WAAW,IAAI,YAAY,EAAE;AAChC,YAAQ,KAAK;KAAE,MAAM;KAAU;KAAa,CAAC;AAC7C,eAAW,IAAI,YAAY;;AAE7B;;AAIF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAC7C,WAAQ,KAAK;IAAE,MAAM;IAAc;IAAc,CAAC;AAClD;;AAIF,MAAI,gBAAgB,KAAK,gBAAgB,MAAM;AAM7C,OAAI,CALc,2BAA2B,IAAI,aAAa,CAM5D,SAAQ,KAAK;IAAE,MAAM;IAAS;IAAc;IAAa,CAAC;OAK1D,SAAQ,KAAK;IAAE,MAAM;IAAU;IAAc;IAAa,CAAC;AAG7D,cAAW,IAAI,YAAY;AAC3B;;GAEF;AAEF,QAAO,EAAE,SAAS"}
@@ -2,127 +2,61 @@
2
2
  const isBlankLine = (line) => line.trim().length === 0;
3
3
  const isFencedCodeDelimiter = (line) => /^\s*```/.test(line);
4
4
  const isHeading = (line) => /^\s*#{1,6}\s+/.test(line);
5
- const isHorizontalRule = (line) => /^(\s*[-*_]){3,}\s*$/.test(line);
6
- const isListItem = (line) => /^\s*([-*+]\s+|\d+\.[\t\s]+)/.test(line);
7
- const isBlockquote = (line) => /^\s*>\s?/.test(line);
8
- const isTableLike = (line) => /\|/.test(line) && !isCodeFenceStart(line);
9
- const isCodeFenceStart = (line) => /^\s*```/.test(line);
5
+ const isFrontmatterDelimiter = (line) => /^\s*---\s*$/.test(line);
10
6
  const trimTrailingNewlines = (text) => text.replace(/\n+$/g, "\n");
11
7
  const segmentDocument = (text) => {
12
8
  const lines = text.split("\n");
13
9
  const blocks = [];
14
10
  let index = 0;
11
+ let insideCodeBlock = false;
12
+ let currentSectionLines = [];
13
+ let currentSectionStartLine = 1;
14
+ const flushCurrentSection = (endIndex) => {
15
+ if (currentSectionLines.length > 0) {
16
+ const rawContent = currentSectionLines.join("\n");
17
+ if (rawContent.trim().length > 0) blocks.push({
18
+ type: "paragraph",
19
+ content: `${trimTrailingNewlines(rawContent)}\n`,
20
+ lineStart: currentSectionStartLine,
21
+ lineEnd: endIndex
22
+ });
23
+ currentSectionLines = [];
24
+ }
25
+ };
15
26
  while (index < lines.length) {
16
- const startIndex = index;
17
27
  const currentLine = lines[index];
18
- if (isFencedCodeDelimiter(currentLine)) {
28
+ if (blocks.length === 0 && isFrontmatterDelimiter(currentLine)) {
29
+ const startLine = index + 1;
19
30
  const contentLines = [currentLine];
20
- index += 1;
21
- while (index < lines.length && !isFencedCodeDelimiter(lines[index])) {
22
- contentLines.push(lines[index]);
23
- index += 1;
24
- }
25
- if (index < lines.length) {
26
- contentLines.push(lines[index]);
27
- index += 1;
28
- }
29
- blocks.push({
30
- type: "code_block",
31
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
32
- lineStart: startIndex + 1,
33
- lineEnd: index
34
- });
35
- continue;
36
- }
37
- if (isHorizontalRule(currentLine)) {
38
- blocks.push({
39
- type: "horizontal_rule",
40
- content: `${currentLine}\n`,
41
- lineStart: startIndex + 1,
42
- lineEnd: startIndex + 1
43
- });
44
- index += 1;
45
- continue;
46
- }
47
- if (isHeading(currentLine)) {
48
- blocks.push({
49
- type: "heading",
50
- content: `${currentLine}\n`,
51
- lineStart: startIndex + 1,
52
- lineEnd: startIndex + 1
53
- });
54
- index += 1;
55
- continue;
56
- }
57
- if (isListItem(currentLine)) {
58
- const contentLines = [];
59
- while (index < lines.length && (isListItem(lines[index]) || !isBlankLine(lines[index]) && /^\s{2,}/.test(lines[index]))) {
60
- contentLines.push(lines[index]);
61
- index += 1;
62
- }
63
- blocks.push({
64
- type: "list_item",
65
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
66
- lineStart: startIndex + 1,
67
- lineEnd: index
68
- });
69
- continue;
70
- }
71
- if (isBlockquote(currentLine)) {
72
- const contentLines = [];
73
- while (index < lines.length && (isBlockquote(lines[index]) || !isBlankLine(lines[index]))) {
31
+ index++;
32
+ while (index < lines.length && !isFrontmatterDelimiter(lines[index])) {
74
33
  contentLines.push(lines[index]);
75
- index += 1;
34
+ index++;
76
35
  }
77
- blocks.push({
78
- type: "blockquote",
79
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
80
- lineStart: startIndex + 1,
81
- lineEnd: index
82
- });
83
- continue;
84
- }
85
- if (isTableLike(currentLine)) {
86
- const contentLines = [];
87
- while (index < lines.length && /\|/.test(lines[index]) && !isBlankLine(lines[index])) {
36
+ if (index < lines.length && isFrontmatterDelimiter(lines[index])) {
88
37
  contentLines.push(lines[index]);
89
- index += 1;
90
- }
91
- blocks.push({
92
- type: "table",
93
- content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
94
- lineStart: startIndex + 1,
95
- lineEnd: index
96
- });
97
- continue;
98
- }
99
- if (!isBlankLine(currentLine)) {
100
- const contentLines = [];
101
- while (index < lines.length && !isBlankLine(lines[index])) {
102
- if (isHeading(lines[index]) || isFencedCodeDelimiter(lines[index]) || isHorizontalRule(lines[index]) || isListItem(lines[index]) || isBlockquote(lines[index]) || isTableLike(lines[index])) break;
103
- contentLines.push(lines[index]);
104
- index += 1;
105
- }
106
- if (index < lines.length && isBlankLine(lines[index])) {
107
- contentLines.push(lines[index]);
108
- index += 1;
38
+ index++;
109
39
  }
110
40
  blocks.push({
111
41
  type: "paragraph",
112
42
  content: `${trimTrailingNewlines(contentLines.join("\n"))}\n`,
113
- lineStart: startIndex + 1,
43
+ lineStart: startLine,
114
44
  lineEnd: index
115
45
  });
116
46
  continue;
117
47
  }
118
- blocks.push({
119
- type: "unknown",
120
- content: `${currentLine}\n`,
121
- lineStart: startIndex + 1,
122
- lineEnd: startIndex + 1
123
- });
124
- index += 1;
48
+ if (isFencedCodeDelimiter(currentLine)) insideCodeBlock = !insideCodeBlock;
49
+ if (!insideCodeBlock && isHeading(currentLine)) {
50
+ if (currentSectionLines.length > 0) flushCurrentSection(index);
51
+ currentSectionStartLine = index + 1;
52
+ currentSectionLines = [currentLine];
53
+ } else {
54
+ if (currentSectionLines.length === 0 && !isBlankLine(currentLine)) currentSectionStartLine = index + 1;
55
+ currentSectionLines.push(currentLine);
56
+ }
57
+ index++;
125
58
  }
59
+ flushCurrentSection(index);
126
60
  return blocks;
127
61
  };
128
62
 
@@ -1 +1 @@
1
- {"version":3,"file":"segmentDocument.mjs","names":["blocks: Block[]","contentLines: string[]"],"sources":["../../../src/translation-alignment/segmentDocument.ts"],"sourcesContent":["import type { Block } from './types';\n\nconst isBlankLine = (line: string): boolean => line.trim().length === 0;\n\nconst isFencedCodeDelimiter = (line: string): boolean => /^\\s*```/.test(line);\n\nconst isHeading = (line: string): boolean => /^\\s*#{1,6}\\s+/.test(line);\n\nconst isHorizontalRule = (line: string): boolean =>\n /^(\\s*[-*_]){3,}\\s*$/.test(line);\n\nconst isListItem = (line: string): boolean =>\n /^\\s*([-*+]\\s+|\\d+\\.[\\t\\s]+)/.test(line);\n\nconst isBlockquote = (line: string): boolean => /^\\s*>\\s?/.test(line);\n\nconst isTableLike = (line: string): boolean =>\n /\\|/.test(line) && !isCodeFenceStart(line);\n\nconst isCodeFenceStart = (line: string): boolean => /^\\s*```/.test(line);\n\nconst trimTrailingNewlines = (text: string): string =>\n text.replace(/\\n+$/g, '\\n');\n\nexport const segmentDocument = (text: string): Block[] => {\n const lines = text.split('\\n');\n const blocks: Block[] = [];\n\n let index = 0;\n while (index < lines.length) {\n const startIndex = index;\n const currentLine = lines[index];\n\n // Code block (fenced)\n if (isFencedCodeDelimiter(currentLine)) {\n const contentLines: string[] = [currentLine];\n index += 1;\n while (index < lines.length && !isFencedCodeDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index += 1;\n }\n if (index < lines.length) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'code_block',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Horizontal rule\n if (isHorizontalRule(currentLine)) {\n blocks.push({\n type: 'horizontal_rule',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n continue;\n }\n\n // Heading\n if (isHeading(currentLine)) {\n blocks.push({\n type: 'heading',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n continue;\n }\n\n // List block (one or more consecutive list items)\n if (isListItem(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n (isListItem(lines[index]) ||\n (!isBlankLine(lines[index]) && /^\\s{2,}/.test(lines[index])))\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'list_item',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Blockquote (may span multiple lines)\n if (isBlockquote(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n (isBlockquote(lines[index]) || !isBlankLine(lines[index]))\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'blockquote',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Table-like (simple heuristic)\n if (isTableLike(currentLine)) {\n const contentLines: string[] = [];\n while (\n index < lines.length &&\n /\\|/.test(lines[index]) &&\n !isBlankLine(lines[index])\n ) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'table',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Paragraph (gathers until blank line)\n if (!isBlankLine(currentLine)) {\n const contentLines: string[] = [];\n while (index < lines.length && !isBlankLine(lines[index])) {\n // stop if we detect a new structural block start\n if (\n isHeading(lines[index]) ||\n isFencedCodeDelimiter(lines[index]) ||\n isHorizontalRule(lines[index]) ||\n isListItem(lines[index]) ||\n isBlockquote(lines[index]) ||\n isTableLike(lines[index])\n ) {\n break;\n }\n contentLines.push(lines[index]);\n index += 1;\n }\n // consume a single trailing blank line if present\n if (index < lines.length && isBlankLine(lines[index])) {\n contentLines.push(lines[index]);\n index += 1;\n }\n blocks.push({\n type: 'paragraph',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startIndex + 1,\n lineEnd: index,\n });\n continue;\n }\n\n // Blank line outside of a paragraph: keep to preserve spacing minimally\n blocks.push({\n type: 'unknown',\n content: `${currentLine}\\n`,\n lineStart: startIndex + 1,\n lineEnd: startIndex + 1,\n });\n index += 1;\n }\n\n return blocks;\n};\n"],"mappings":";AAEA,MAAM,eAAe,SAA0B,KAAK,MAAM,CAAC,WAAW;AAEtE,MAAM,yBAAyB,SAA0B,UAAU,KAAK,KAAK;AAE7E,MAAM,aAAa,SAA0B,gBAAgB,KAAK,KAAK;AAEvE,MAAM,oBAAoB,SACxB,sBAAsB,KAAK,KAAK;AAElC,MAAM,cAAc,SAClB,8BAA8B,KAAK,KAAK;AAE1C,MAAM,gBAAgB,SAA0B,WAAW,KAAK,KAAK;AAErE,MAAM,eAAe,SACnB,KAAK,KAAK,KAAK,IAAI,CAAC,iBAAiB,KAAK;AAE5C,MAAM,oBAAoB,SAA0B,UAAU,KAAK,KAAK;AAExE,MAAM,wBAAwB,SAC5B,KAAK,QAAQ,SAAS,KAAK;AAE7B,MAAa,mBAAmB,SAA0B;CACxD,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,MAAMA,SAAkB,EAAE;CAE1B,IAAI,QAAQ;AACZ,QAAO,QAAQ,MAAM,QAAQ;EAC3B,MAAM,aAAa;EACnB,MAAM,cAAc,MAAM;AAG1B,MAAI,sBAAsB,YAAY,EAAE;GACtC,MAAMC,eAAyB,CAAC,YAAY;AAC5C,YAAS;AACT,UAAO,QAAQ,MAAM,UAAU,CAAC,sBAAsB,MAAM,OAAO,EAAE;AACnE,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,OAAI,QAAQ,MAAM,QAAQ;AACxB,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW,aAAa;IACxB,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,iBAAiB,YAAY,EAAE;AACjC,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,YAAY;IACxB,WAAW,aAAa;IACxB,SAAS,aAAa;IACvB,CAAC;AACF,YAAS;AACT;;AAIF,MAAI,UAAU,YAAY,EAAE;AAC1B,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,YAAY;IACxB,WAAW,aAAa;IACxB,SAAS,aAAa;IACvB,CAAC;AACF,YAAS;AACT;;AAIF,MAAI,WAAW,YAAY,EAAE;GAC3B,MAAMA,eAAyB,EAAE;AACjC,UACE,QAAQ,MAAM,WACb,WAAW,MAAM,OAAO,IACtB,CAAC,YAAY,MAAM,OAAO,IAAI,UAAU,KAAK,MAAM,OAAO,GAC7D;AACA,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW,aAAa;IACxB,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,aAAa,YAAY,EAAE;GAC7B,MAAMA,eAAyB,EAAE;AACjC,UACE,QAAQ,MAAM,WACb,aAAa,MAAM,OAAO,IAAI,CAAC,YAAY,MAAM,OAAO,GACzD;AACA,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW,aAAa;IACxB,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,YAAY,YAAY,EAAE;GAC5B,MAAMA,eAAyB,EAAE;AACjC,UACE,QAAQ,MAAM,UACd,KAAK,KAAK,MAAM,OAAO,IACvB,CAAC,YAAY,MAAM,OAAO,EAC1B;AACA,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW,aAAa;IACxB,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,CAAC,YAAY,YAAY,EAAE;GAC7B,MAAMA,eAAyB,EAAE;AACjC,UAAO,QAAQ,MAAM,UAAU,CAAC,YAAY,MAAM,OAAO,EAAE;AAEzD,QACE,UAAU,MAAM,OAAO,IACvB,sBAAsB,MAAM,OAAO,IACnC,iBAAiB,MAAM,OAAO,IAC9B,WAAW,MAAM,OAAO,IACxB,aAAa,MAAM,OAAO,IAC1B,YAAY,MAAM,OAAO,CAEzB;AAEF,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAGX,OAAI,QAAQ,MAAM,UAAU,YAAY,MAAM,OAAO,EAAE;AACrD,iBAAa,KAAK,MAAM,OAAO;AAC/B,aAAS;;AAEX,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW,aAAa;IACxB,SAAS;IACV,CAAC;AACF;;AAIF,SAAO,KAAK;GACV,MAAM;GACN,SAAS,GAAG,YAAY;GACxB,WAAW,aAAa;GACxB,SAAS,aAAa;GACvB,CAAC;AACF,WAAS;;AAGX,QAAO"}
1
+ {"version":3,"file":"segmentDocument.mjs","names":["blocks: Block[]","currentSectionLines: string[]","contentLines: string[]"],"sources":["../../../src/translation-alignment/segmentDocument.ts"],"sourcesContent":["import type { Block } from './types';\n\nconst isBlankLine = (line: string): boolean => line.trim().length === 0;\nconst isFencedCodeDelimiter = (line: string): boolean => /^\\s*```/.test(line);\nconst isHeading = (line: string): boolean => /^\\s*#{1,6}\\s+/.test(line);\nconst isFrontmatterDelimiter = (line: string): boolean =>\n /^\\s*---\\s*$/.test(line);\nconst trimTrailingNewlines = (text: string): string =>\n text.replace(/\\n+$/g, '\\n');\n\nexport const segmentDocument = (text: string): Block[] => {\n const lines = text.split('\\n');\n const blocks: Block[] = [];\n\n let index = 0;\n let insideCodeBlock = false;\n\n // Buffers\n let currentSectionLines: string[] = [];\n let currentSectionStartLine = 1;\n\n const flushCurrentSection = (endIndex: number) => {\n if (currentSectionLines.length > 0) {\n // Filter out leading blank lines from the block content to keep it clean,\n // but strictly speaking, we just want to ensure non-empty content.\n const rawContent = currentSectionLines.join('\\n');\n\n if (rawContent.trim().length > 0) {\n blocks.push({\n type: 'paragraph', // Generic type\n content: `${trimTrailingNewlines(rawContent)}\\n`,\n lineStart: currentSectionStartLine,\n lineEnd: endIndex,\n });\n }\n currentSectionLines = [];\n }\n };\n\n while (index < lines.length) {\n const currentLine = lines[index];\n\n // 1. Handle Frontmatter (Must be at start of file)\n if (blocks.length === 0 && isFrontmatterDelimiter(currentLine)) {\n const startLine = index + 1;\n const contentLines: string[] = [currentLine];\n index++;\n\n while (index < lines.length && !isFrontmatterDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index++;\n }\n\n if (index < lines.length && isFrontmatterDelimiter(lines[index])) {\n contentLines.push(lines[index]);\n index++;\n }\n\n blocks.push({\n type: 'paragraph',\n content: `${trimTrailingNewlines(contentLines.join('\\n'))}\\n`,\n lineStart: startLine,\n lineEnd: index,\n });\n continue;\n }\n\n // 2. Track Code Blocks (Headers inside code blocks are ignored)\n if (isFencedCodeDelimiter(currentLine)) {\n insideCodeBlock = !insideCodeBlock;\n }\n\n const isHeader = !insideCodeBlock && isHeading(currentLine);\n\n // 3. Split on Headers\n if (isHeader) {\n // If we have accumulated content, flush it as the previous block\n if (currentSectionLines.length > 0) {\n flushCurrentSection(index);\n }\n // Start a new section with this header\n currentSectionStartLine = index + 1;\n currentSectionLines = [currentLine];\n } else {\n // Accumulate content\n if (currentSectionLines.length === 0 && !isBlankLine(currentLine)) {\n currentSectionStartLine = index + 1;\n }\n currentSectionLines.push(currentLine);\n }\n\n index++;\n }\n\n // Flush remaining content\n flushCurrentSection(index);\n\n return blocks;\n};\n"],"mappings":";AAEA,MAAM,eAAe,SAA0B,KAAK,MAAM,CAAC,WAAW;AACtE,MAAM,yBAAyB,SAA0B,UAAU,KAAK,KAAK;AAC7E,MAAM,aAAa,SAA0B,gBAAgB,KAAK,KAAK;AACvE,MAAM,0BAA0B,SAC9B,cAAc,KAAK,KAAK;AAC1B,MAAM,wBAAwB,SAC5B,KAAK,QAAQ,SAAS,KAAK;AAE7B,MAAa,mBAAmB,SAA0B;CACxD,MAAM,QAAQ,KAAK,MAAM,KAAK;CAC9B,MAAMA,SAAkB,EAAE;CAE1B,IAAI,QAAQ;CACZ,IAAI,kBAAkB;CAGtB,IAAIC,sBAAgC,EAAE;CACtC,IAAI,0BAA0B;CAE9B,MAAM,uBAAuB,aAAqB;AAChD,MAAI,oBAAoB,SAAS,GAAG;GAGlC,MAAM,aAAa,oBAAoB,KAAK,KAAK;AAEjD,OAAI,WAAW,MAAM,CAAC,SAAS,EAC7B,QAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,WAAW,CAAC;IAC7C,WAAW;IACX,SAAS;IACV,CAAC;AAEJ,yBAAsB,EAAE;;;AAI5B,QAAO,QAAQ,MAAM,QAAQ;EAC3B,MAAM,cAAc,MAAM;AAG1B,MAAI,OAAO,WAAW,KAAK,uBAAuB,YAAY,EAAE;GAC9D,MAAM,YAAY,QAAQ;GAC1B,MAAMC,eAAyB,CAAC,YAAY;AAC5C;AAEA,UAAO,QAAQ,MAAM,UAAU,CAAC,uBAAuB,MAAM,OAAO,EAAE;AACpE,iBAAa,KAAK,MAAM,OAAO;AAC/B;;AAGF,OAAI,QAAQ,MAAM,UAAU,uBAAuB,MAAM,OAAO,EAAE;AAChE,iBAAa,KAAK,MAAM,OAAO;AAC/B;;AAGF,UAAO,KAAK;IACV,MAAM;IACN,SAAS,GAAG,qBAAqB,aAAa,KAAK,KAAK,CAAC,CAAC;IAC1D,WAAW;IACX,SAAS;IACV,CAAC;AACF;;AAIF,MAAI,sBAAsB,YAAY,CACpC,mBAAkB,CAAC;AAMrB,MAHiB,CAAC,mBAAmB,UAAU,YAAY,EAG7C;AAEZ,OAAI,oBAAoB,SAAS,EAC/B,qBAAoB,MAAM;AAG5B,6BAA0B,QAAQ;AAClC,yBAAsB,CAAC,YAAY;SAC9B;AAEL,OAAI,oBAAoB,WAAW,KAAK,CAAC,YAAY,YAAY,CAC/D,2BAA0B,QAAQ;AAEpC,uBAAoB,KAAK,YAAY;;AAGvC;;AAIF,qBAAoB,MAAM;AAE1B,QAAO"}
@@ -45,7 +45,8 @@ const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true)
45
45
  const checkAIAccess = async (configuration, aiOptions, shouldCheckConfigConsistency = true) => {
46
46
  const appLogger = getAppLogger(configuration);
47
47
  const hasCMSAuth = Boolean(configuration.editor.clientId && configuration.editor.clientSecret);
48
- if (Boolean(configuration.ai?.apiKey || aiOptions?.apiKey)) return true;
48
+ const isOllama = configuration.ai?.provider === "ollama" || aiOptions?.provider === "ollama";
49
+ if (Boolean(configuration.ai?.apiKey || aiOptions?.apiKey) || isOllama) return true;
49
50
  if (!hasCMSAuth) {
50
51
  appLogger([
51
52
  "AI options or API key not provided. You can either retreive the CMS access key on",
@@ -1 +1 @@
1
- {"version":3,"file":"checkAccess.mjs","names":[],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n ANSIColors,\n colorize,\n extractErrorMessage,\n getAppLogger,\n} from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\nexport const checkCMSAuth = async (\n configuration: IntlayerConfig,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration, {\n config: {\n prefix: '',\n },\n });\n\n const hasCMSAuth =\n configuration.editor.clientId && configuration.editor.clientSecret;\n if (!hasCMSAuth) {\n appLogger(\n [\n 'CMS auth not provided. You can either retreive the CMS access key on',\n colorize('https://intlayer.org/dahboard', ANSIColors.GREY),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'error',\n }\n );\n\n return false;\n }\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n try {\n const result = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const project = result.data?.project;\n\n if (!project) {\n appLogger('Project not found');\n\n return true;\n }\n\n if (project.configuration && shouldCheckConfigConsistency) {\n try {\n // Recursively check if project.configuration (subset) matches configuration (superset)\n checkConfigConsistency(project.configuration, configuration);\n } catch {\n appLogger(\n [\n 'Remote configuration is not up to date. The project configuration does not match the local configuration.',\n 'You can push the configuration by running',\n colorize('npx intlayer push', ANSIColors.CYAN),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/cli/push',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'warn',\n }\n );\n }\n }\n } catch (error) {\n const message = extractErrorMessage(error);\n\n appLogger(message, {\n level: 'error',\n });\n return false;\n }\n\n return true;\n};\n\nexport const checkAIAccess = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n const hasCMSAuth = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n const hasHisOwnAIAPIKey = Boolean(\n configuration.ai?.apiKey || aiOptions?.apiKey\n );\n\n if (hasHisOwnAIAPIKey) {\n return true;\n }\n\n // User need to provide either his own AI API key or the CMS auth\n if (!hasCMSAuth) {\n appLogger(\n [\n 'AI options or API key not provided. You can either retreive the CMS access key on',\n colorize('https://intlayer.org/dahboard', ANSIColors.GREY),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '. Alternatively, you can add your own OpenAI API key in the settings',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/configuration',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'error',\n }\n );\n\n return false;\n }\n\n // If the user do not have his own AI API key, we need to check the CMS auth\n return await checkCMSAuth(configuration, shouldCheckConfigConsistency);\n};\n"],"mappings":";;;;;AAWA,MAAa,eAAe,OAC1B,eACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,eAAe,EAC5C,QAAQ,EACN,QAAQ,IACT,EACF,CAAC;AAIF,KAAI,EADF,cAAc,OAAO,YAAY,cAAc,OAAO,eACvC;AACf,YACE;GACE;GACA,SAAS,iCAAiC,WAAW,KAAK;GAC1D,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,wCAAwC,WAAW,KAAK;GACjE,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EACE,OAAO,SACR,CACF;AAED,SAAO;;CAET,MAAM,cAAc,oBAAoB,QAAW,cAAc;AAEjE,KAAI;EAGF,MAAM,WAFS,MAAM,YAAY,MAAM,sBAAsB,EAEtC,MAAM;AAE7B,MAAI,CAAC,SAAS;AACZ,aAAU,oBAAoB;AAE9B,UAAO;;AAGT,MAAI,QAAQ,iBAAiB,6BAC3B,KAAI;AAEF,0BAAuB,QAAQ,eAAe,cAAc;UACtD;AACN,aACE;IACE;IACA;IACA,SAAS,qBAAqB,WAAW,KAAK;IAC9C,SAAS,aAAa,WAAW,UAAU;IAC3C,SACE,6CACA,WAAW,KACZ;IACD,SAAS,KAAK,WAAW,UAAU;IACnC;IACD,EACD,EACE,OAAO,QACR,CACF;;UAGE,OAAO;AAGd,YAFgB,oBAAoB,MAAM,EAEvB,EACjB,OAAO,SACR,CAAC;AACF,SAAO;;AAGT,QAAO;;AAGT,MAAa,gBAAgB,OAC3B,eACA,WACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,aAAa,QACjB,cAAc,OAAO,YAAY,cAAc,OAAO,aACvD;AAKD,KAJ0B,QACxB,cAAc,IAAI,UAAU,WAAW,OACxC,CAGC,QAAO;AAIT,KAAI,CAAC,YAAY;AACf,YACE;GACE;GACA,SAAS,iCAAiC,WAAW,KAAK;GAC1D,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,wCAAwC,WAAW,KAAK;GACjE,SAAS,KAAK,WAAW,UAAU;GACnC;GACA,SAAS,aAAa,WAAW,UAAU;GAC3C,SACE,kDACA,WAAW,KACZ;GACD,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EACE,OAAO,SACR,CACF;AAED,SAAO;;AAIT,QAAO,MAAM,aAAa,eAAe,6BAA6B"}
1
+ {"version":3,"file":"checkAccess.mjs","names":[],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n ANSIColors,\n colorize,\n extractErrorMessage,\n getAppLogger,\n} from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\nexport const checkCMSAuth = async (\n configuration: IntlayerConfig,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration, {\n config: {\n prefix: '',\n },\n });\n\n const hasCMSAuth =\n configuration.editor.clientId && configuration.editor.clientSecret;\n if (!hasCMSAuth) {\n appLogger(\n [\n 'CMS auth not provided. You can either retreive the CMS access key on',\n colorize('https://intlayer.org/dahboard', ANSIColors.GREY),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'error',\n }\n );\n\n return false;\n }\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n try {\n const result = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const project = result.data?.project;\n\n if (!project) {\n appLogger('Project not found');\n\n return true;\n }\n\n if (project.configuration && shouldCheckConfigConsistency) {\n try {\n // Recursively check if project.configuration (subset) matches configuration (superset)\n checkConfigConsistency(project.configuration, configuration);\n } catch {\n appLogger(\n [\n 'Remote configuration is not up to date. The project configuration does not match the local configuration.',\n 'You can push the configuration by running',\n colorize('npx intlayer push', ANSIColors.CYAN),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/cli/push',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'warn',\n }\n );\n }\n }\n } catch (error) {\n const message = extractErrorMessage(error);\n\n appLogger(message, {\n level: 'error',\n });\n return false;\n }\n\n return true;\n};\n\nexport const checkAIAccess = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n const hasCMSAuth = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n const isOllama =\n configuration.ai?.provider === 'ollama' || aiOptions?.provider === 'ollama';\n const hasHisOwnAIAPIKey = Boolean(\n configuration.ai?.apiKey || aiOptions?.apiKey\n );\n\n if (hasHisOwnAIAPIKey || isOllama) {\n return true;\n }\n\n // User need to provide either his own AI API key or the CMS auth\n if (!hasCMSAuth) {\n appLogger(\n [\n 'AI options or API key not provided. You can either retreive the CMS access key on',\n colorize('https://intlayer.org/dahboard', ANSIColors.GREY),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '. Alternatively, you can add your own OpenAI API key in the settings',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/configuration',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n {\n level: 'error',\n }\n );\n\n return false;\n }\n\n // If the user do not have his own AI API key, we need to check the CMS auth\n return await checkCMSAuth(configuration, shouldCheckConfigConsistency);\n};\n"],"mappings":";;;;;AAWA,MAAa,eAAe,OAC1B,eACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,eAAe,EAC5C,QAAQ,EACN,QAAQ,IACT,EACF,CAAC;AAIF,KAAI,EADF,cAAc,OAAO,YAAY,cAAc,OAAO,eACvC;AACf,YACE;GACE;GACA,SAAS,iCAAiC,WAAW,KAAK;GAC1D,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,wCAAwC,WAAW,KAAK;GACjE,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EACE,OAAO,SACR,CACF;AAED,SAAO;;CAET,MAAM,cAAc,oBAAoB,QAAW,cAAc;AAEjE,KAAI;EAGF,MAAM,WAFS,MAAM,YAAY,MAAM,sBAAsB,EAEtC,MAAM;AAE7B,MAAI,CAAC,SAAS;AACZ,aAAU,oBAAoB;AAE9B,UAAO;;AAGT,MAAI,QAAQ,iBAAiB,6BAC3B,KAAI;AAEF,0BAAuB,QAAQ,eAAe,cAAc;UACtD;AACN,aACE;IACE;IACA;IACA,SAAS,qBAAqB,WAAW,KAAK;IAC9C,SAAS,aAAa,WAAW,UAAU;IAC3C,SACE,6CACA,WAAW,KACZ;IACD,SAAS,KAAK,WAAW,UAAU;IACnC;IACD,EACD,EACE,OAAO,QACR,CACF;;UAGE,OAAO;AAGd,YAFgB,oBAAoB,MAAM,EAEvB,EACjB,OAAO,SACR,CAAC;AACF,SAAO;;AAGT,QAAO;;AAGT,MAAa,gBAAgB,OAC3B,eACA,WACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,aAAa,QACjB,cAAc,OAAO,YAAY,cAAc,OAAO,aACvD;CACD,MAAM,WACJ,cAAc,IAAI,aAAa,YAAY,WAAW,aAAa;AAKrE,KAJ0B,QACxB,cAAc,IAAI,UAAU,WAAW,OACxC,IAEwB,SACvB,QAAO;AAIT,KAAI,CAAC,YAAY;AACf,YACE;GACE;GACA,SAAS,iCAAiC,WAAW,KAAK;GAC1D,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,wCAAwC,WAAW,KAAK;GACjE,SAAS,KAAK,WAAW,UAAU;GACnC;GACA,SAAS,aAAa,WAAW,UAAU;GAC3C,SACE,kDACA,WAAW,KACZ;GACD,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EACE,OAAO,SACR,CACF;AAED,SAAO;;AAIT,QAAO,MAAM,aAAa,eAAe,6BAA6B"}
@@ -20,28 +20,37 @@ const logAIConfig = (aiOptions, appLogger) => {
20
20
  */
21
21
  const setupAI = async (configuration, aiOptions) => {
22
22
  const appLogger = getAppLogger(configuration);
23
- const hasAIAccess = await checkAIAccess(configuration, aiOptions);
24
- if (aiOptions?.apiKey) try {
25
- const aiClient = await import("@intlayer/ai");
23
+ if (aiOptions?.apiKey || aiOptions?.provider === "ollama" || configuration.ai?.apiKey || configuration.ai?.provider === "ollama") {
24
+ let aiClient;
25
+ try {
26
+ aiClient = await import("@intlayer/ai");
27
+ } catch {
28
+ appLogger([
29
+ colorize("Using your API key, you can install the", ANSIColors.GREY),
30
+ colorize("@intlayer/ai", ANSIColors.GREY_LIGHT),
31
+ colorize("package to run the process locally, with no dependency on the Intlayer server", ANSIColors.GREY)
32
+ ], { level: "warn" });
33
+ const hasAIAccess$1 = await checkAIAccess(configuration, aiOptions);
34
+ logAIConfig(aiOptions ?? {}, appLogger);
35
+ return {
36
+ isCustomAI: false,
37
+ hasAIAccess: hasAIAccess$1
38
+ };
39
+ }
26
40
  appLogger([colorize("@intlayer/ai", ANSIColors.GREY_LIGHT), colorize("found - Run process locally", ANSIColors.GREY_DARK)]);
27
41
  const aiConfig = await aiClient.getAIConfig({
28
42
  userOptions: aiOptions,
29
43
  accessType: ["public"]
30
44
  });
31
- logAIConfig(aiOptions, appLogger);
45
+ logAIConfig(aiOptions ?? {}, appLogger);
32
46
  return {
33
47
  aiClient,
34
48
  aiConfig,
35
49
  isCustomAI: true,
36
- hasAIAccess
50
+ hasAIAccess: true
37
51
  };
38
- } catch {
39
- appLogger([
40
- colorize("Using your API key, you can install the", ANSIColors.GREY),
41
- colorize("@intlayer/ai", ANSIColors.GREY_LIGHT),
42
- colorize("package to run the process locally, with no dependency on the Intlayer server", ANSIColors.GREY)
43
- ], { level: "warn" });
44
52
  }
53
+ const hasAIAccess = await checkAIAccess(configuration, aiOptions);
45
54
  logAIConfig(aiOptions ?? {}, appLogger);
46
55
  return {
47
56
  isCustomAI: false,
@@ -1 +1 @@
1
- {"version":3,"file":"setupAI.mjs","names":[],"sources":["../../../src/utils/setupAI.ts"],"sourcesContent":["import type { AIConfig, AIOptions } from '@intlayer/ai';\nimport {\n ANSIColors,\n colorize,\n getAppLogger,\n type logger,\n} from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { checkAIAccess } from './checkAccess';\n\nexport type AIClient = typeof import('@intlayer/ai');\n\ntype SetupAIResult = {\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n isCustomAI: boolean;\n hasAIAccess: boolean;\n};\n\n// Disable warnings from the AI SDK\nglobalThis.AI_SDK_LOG_WARNINGS = false;\n\nconst logAIConfig = (aiOptions: AIOptions, appLogger: typeof logger) => {\n appLogger([\n colorize('Provider:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.provider ?? '(default)', ANSIColors.BLUE),\n colorize('- Model:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.model ?? '(default)', ANSIColors.BLUE),\n colorize('- API Key:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.apiKey ? '✓' : '(not set)', ANSIColors.BLUE),\n ]);\n};\n\n/**\n * Checks if the @intlayer/ai package is available and configured when an API key is provided.\n * If API key is present but package is missing, logs a warning.\n * Also checks if the user has access to AI (either via local key or CMS auth).\n */\nexport const setupAI = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions\n): Promise<SetupAIResult | undefined> => {\n const appLogger = getAppLogger(configuration);\n\n const hasAIAccess = await checkAIAccess(configuration, aiOptions);\n\n if (aiOptions?.apiKey) {\n try {\n // Dynamically import the AI package if an API key is provided\n const aiClient = await import('@intlayer/ai');\n\n appLogger([\n colorize('@intlayer/ai', ANSIColors.GREY_LIGHT),\n colorize('found - Run process locally', ANSIColors.GREY_DARK),\n ]);\n\n const aiConfig = await aiClient.getAIConfig({\n userOptions: aiOptions,\n accessType: ['public'],\n });\n\n logAIConfig(aiOptions, appLogger);\n\n return {\n aiClient,\n aiConfig,\n isCustomAI: true,\n hasAIAccess,\n };\n } catch {\n appLogger(\n [\n colorize('Using your API key, you can install the', ANSIColors.GREY),\n colorize('@intlayer/ai', ANSIColors.GREY_LIGHT),\n colorize(\n 'package to run the process locally, with no dependency on the Intlayer server',\n ANSIColors.GREY\n ),\n ],\n {\n level: 'warn',\n }\n );\n }\n }\n\n logAIConfig(aiOptions ?? {}, appLogger);\n\n return {\n isCustomAI: false,\n hasAIAccess,\n };\n};\n"],"mappings":";;;;AAoBA,WAAW,sBAAsB;AAEjC,MAAM,eAAe,WAAsB,cAA6B;AACtE,WAAU;EACR,SAAS,aAAa,WAAW,UAAU;EAC3C,SAAS,WAAW,YAAY,aAAa,WAAW,KAAK;EAC7D,SAAS,YAAY,WAAW,UAAU;EAC1C,SAAS,WAAW,SAAS,aAAa,WAAW,KAAK;EAC1D,SAAS,cAAc,WAAW,UAAU;EAC5C,SAAS,WAAW,SAAS,MAAM,aAAa,WAAW,KAAK;EACjE,CAAC;;;;;;;AAQJ,MAAa,UAAU,OACrB,eACA,cACuC;CACvC,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,cAAc,MAAM,cAAc,eAAe,UAAU;AAEjE,KAAI,WAAW,OACb,KAAI;EAEF,MAAM,WAAW,MAAM,OAAO;AAE9B,YAAU,CACR,SAAS,gBAAgB,WAAW,WAAW,EAC/C,SAAS,+BAA+B,WAAW,UAAU,CAC9D,CAAC;EAEF,MAAM,WAAW,MAAM,SAAS,YAAY;GAC1C,aAAa;GACb,YAAY,CAAC,SAAS;GACvB,CAAC;AAEF,cAAY,WAAW,UAAU;AAEjC,SAAO;GACL;GACA;GACA,YAAY;GACZ;GACD;SACK;AACN,YACE;GACE,SAAS,2CAA2C,WAAW,KAAK;GACpE,SAAS,gBAAgB,WAAW,WAAW;GAC/C,SACE,iFACA,WAAW,KACZ;GACF,EACD,EACE,OAAO,QACR,CACF;;AAIL,aAAY,aAAa,EAAE,EAAE,UAAU;AAEvC,QAAO;EACL,YAAY;EACZ;EACD"}
1
+ {"version":3,"file":"setupAI.mjs","names":["aiClient: AIClient | undefined","hasAIAccess"],"sources":["../../../src/utils/setupAI.ts"],"sourcesContent":["import type { AIConfig, AIOptions } from '@intlayer/ai';\nimport {\n ANSIColors,\n colorize,\n getAppLogger,\n type logger,\n} from '@intlayer/config';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { checkAIAccess } from './checkAccess';\n\nexport type AIClient = typeof import('@intlayer/ai');\n\ntype SetupAIResult = {\n aiClient?: AIClient;\n aiConfig?: AIConfig;\n isCustomAI: boolean;\n hasAIAccess: boolean;\n};\n\n// Disable warnings from the AI SDK\nglobalThis.AI_SDK_LOG_WARNINGS = false;\n\nconst logAIConfig = (aiOptions: AIOptions, appLogger: typeof logger) => {\n appLogger([\n colorize('Provider:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.provider ?? '(default)', ANSIColors.BLUE),\n colorize('- Model:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.model ?? '(default)', ANSIColors.BLUE),\n colorize('- API Key:', ANSIColors.GREY_DARK),\n colorize(aiOptions?.apiKey ? '✓' : '(not set)', ANSIColors.BLUE),\n ]);\n};\n\n/**\n * Checks if the @intlayer/ai package is available and configured when an API key is provided.\n * If API key is present but package is missing, logs a warning.\n * Also checks if the user has access to AI (either via local key or CMS auth).\n */\nexport const setupAI = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions\n): Promise<SetupAIResult | undefined> => {\n const appLogger = getAppLogger(configuration);\n\n const isLocalAI =\n aiOptions?.apiKey ||\n aiOptions?.provider === 'ollama' ||\n configuration.ai?.apiKey ||\n configuration.ai?.provider === 'ollama';\n\n if (isLocalAI) {\n // Try to import the AI package for local AI usage\n let aiClient: AIClient | undefined;\n\n try {\n aiClient = await import('@intlayer/ai');\n } catch {\n // Package not installed - log warning and fall back to backend\n appLogger(\n [\n colorize('Using your API key, you can install the', ANSIColors.GREY),\n colorize('@intlayer/ai', ANSIColors.GREY_LIGHT),\n colorize(\n 'package to run the process locally, with no dependency on the Intlayer server',\n ANSIColors.GREY\n ),\n ],\n {\n level: 'warn',\n }\n );\n\n // Fall back to backend API check\n const hasAIAccess = await checkAIAccess(configuration, aiOptions);\n logAIConfig(aiOptions ?? {}, appLogger);\n return {\n isCustomAI: false,\n hasAIAccess,\n };\n }\n\n // Package found - now configure it (errors here should propagate, not fall back)\n appLogger([\n colorize('@intlayer/ai', ANSIColors.GREY_LIGHT),\n colorize('found - Run process locally', ANSIColors.GREY_DARK),\n ]);\n\n const aiConfig = await aiClient.getAIConfig({\n userOptions: aiOptions,\n accessType: ['public'],\n });\n\n logAIConfig(aiOptions ?? {}, appLogger);\n\n return {\n aiClient,\n aiConfig,\n isCustomAI: true,\n hasAIAccess: true, // Local AI always has access\n };\n }\n\n // No local AI configured - use backend API\n const hasAIAccess = await checkAIAccess(configuration, aiOptions);\n logAIConfig(aiOptions ?? {}, appLogger);\n\n return {\n isCustomAI: false,\n hasAIAccess,\n };\n};\n"],"mappings":";;;;AAoBA,WAAW,sBAAsB;AAEjC,MAAM,eAAe,WAAsB,cAA6B;AACtE,WAAU;EACR,SAAS,aAAa,WAAW,UAAU;EAC3C,SAAS,WAAW,YAAY,aAAa,WAAW,KAAK;EAC7D,SAAS,YAAY,WAAW,UAAU;EAC1C,SAAS,WAAW,SAAS,aAAa,WAAW,KAAK;EAC1D,SAAS,cAAc,WAAW,UAAU;EAC5C,SAAS,WAAW,SAAS,MAAM,aAAa,WAAW,KAAK;EACjE,CAAC;;;;;;;AAQJ,MAAa,UAAU,OACrB,eACA,cACuC;CACvC,MAAM,YAAY,aAAa,cAAc;AAQ7C,KALE,WAAW,UACX,WAAW,aAAa,YACxB,cAAc,IAAI,UAClB,cAAc,IAAI,aAAa,UAElB;EAEb,IAAIA;AAEJ,MAAI;AACF,cAAW,MAAM,OAAO;UAClB;AAEN,aACE;IACE,SAAS,2CAA2C,WAAW,KAAK;IACpE,SAAS,gBAAgB,WAAW,WAAW;IAC/C,SACE,iFACA,WAAW,KACZ;IACF,EACD,EACE,OAAO,QACR,CACF;GAGD,MAAMC,gBAAc,MAAM,cAAc,eAAe,UAAU;AACjE,eAAY,aAAa,EAAE,EAAE,UAAU;AACvC,UAAO;IACL,YAAY;IACZ;IACD;;AAIH,YAAU,CACR,SAAS,gBAAgB,WAAW,WAAW,EAC/C,SAAS,+BAA+B,WAAW,UAAU,CAC9D,CAAC;EAEF,MAAM,WAAW,MAAM,SAAS,YAAY;GAC1C,aAAa;GACb,YAAY,CAAC,SAAS;GACvB,CAAC;AAEF,cAAY,aAAa,EAAE,EAAE,UAAU;AAEvC,SAAO;GACL;GACA;GACA,YAAY;GACZ,aAAa;GACd;;CAIH,MAAM,cAAc,MAAM,cAAc,eAAe,UAAU;AACjE,aAAY,aAAa,EAAE,EAAE,UAAU;AAEvC,QAAO;EACL,YAAY;EACZ;EACD"}
@@ -0,0 +1,5 @@
1
+ //#region src/ci.d.ts
2
+ declare const runCI: (commands: string[]) => Promise<void>;
3
+ //#endregion
4
+ export { runCI };
5
+ //# sourceMappingURL=ci.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.d.ts","names":[],"sources":["../../src/ci.ts"],"sourcesContent":[],"mappings":";cAuBa,+BAAiC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","names":[],"sources":["../../src/cli.ts"],"sourcesContent":[],"mappings":";;;cAmCa;KAwIR,UAAA;EAxIQ,MAAA,CAAA,EAAA,MAEA;EAsIR,OAAA,CAAA,EAAA,OAAU;AAKf,CAAA;AA2Da,KA3DD,oBAAA,GAyoBX;;;;;IApoBG;;;;;;;;;cAsDS,cAAa"}
1
+ {"version":3,"file":"cli.d.ts","names":[],"sources":["../../src/cli.ts"],"sourcesContent":[],"mappings":";;;cAqCa;KAwIR,UAAA;EAxIQ,MAAA,CAAA,EAAA,MAEA;EAsIR,OAAA,CAAA,EAAA,OAAU;AAKf,CAAA;AA2Da,KA3DD,oBAAA,GA2tBX;;;;;IAttBG;;;;;;;;;cAsDS,cAAa"}
@@ -7,11 +7,11 @@ import { liveSync } from "./liveSync.js";
7
7
  import { pull } from "./pull.js";
8
8
  import { push } from "./push/push.js";
9
9
  import { pushConfig } from "./pushConfig.js";
10
- import { reviewDoc } from "./reviewDoc.js";
10
+ import { reviewDoc } from "./reviewDoc/reviewDoc.js";
11
11
  import { listMissingTranslations, listMissingTranslationsWithConfig } from "./test/listMissingTranslations.js";
12
12
  import { testMissingTranslations } from "./test/test.js";
13
13
  import "./test/index.js";
14
14
  import { transform } from "./transform.js";
15
- import { translateDoc, translateFile } from "./translateDoc.js";
15
+ import { translateDoc } from "./translateDoc/translateDoc.js";
16
16
  export * from "@intlayer/chokidar";
17
- export { ConfigurationOptions, FillOptions, build, dirname, fill, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, liveSync, pull, push, pushConfig, reviewDoc, setAPI, startEditor, testMissingTranslations, transform, translateDoc, translateFile };
17
+ export { ConfigurationOptions, FillOptions, build, dirname, fill, listContentDeclaration, listContentDeclarationRows, listMissingTranslations, listMissingTranslationsWithConfig, liveSync, pull, push, pushConfig, reviewDoc, setAPI, startEditor, testMissingTranslations, transform, translateDoc };
@@ -3,6 +3,8 @@ import { GetConfigurationOptions } from "@intlayer/config";
3
3
  //#region src/listContentDeclaration.d.ts
4
4
  type ListContentDeclarationOptions = {
5
5
  configOptions?: GetConfigurationOptions;
6
+ json?: boolean;
7
+ absolute?: boolean;
6
8
  };
7
9
  declare const listContentDeclarationRows: (options?: ListContentDeclarationOptions) => {
8
10
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"listContentDeclaration.d.ts","names":[],"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":[],"mappings":";;;KAYK,6BAAA;kBACa;AAJQ,CAAA;AAOb,cAAA,0BACD,EAAA,CAAA,OAA6B,CAA7B,EAAA,6BAA6B,EAAA,GAAA;EAe5B,GAAA,EAAA,MAAA;;;cAAA,mCACD"}
1
+ {"version":3,"file":"listContentDeclaration.d.ts","names":[],"sources":["../../src/listContentDeclaration.ts"],"sourcesContent":[],"mappings":";;;KAYK,6BAAA;kBACa;EADb,IAAA,CAAA,EAAA,OAAA;EAMQ,QAAA,CAAA,EAAA,OAAA;AAkBb,CAAA;cAlBa,uCACD;;;;cAiBC,mCACD"}
@@ -0,0 +1,11 @@
1
+ import { ListProjectsOptions } from "@intlayer/chokidar";
2
+
3
+ //#region src/listProjects.d.ts
4
+ type ListProjectsCommandOptions = ListProjectsOptions & {
5
+ json?: boolean;
6
+ absolute?: boolean;
7
+ };
8
+ declare const listProjectsCommand: (options?: ListProjectsCommandOptions) => Promise<void>;
9
+ //#endregion
10
+ export { ListProjectsCommandOptions, listProjectsCommand };
11
+ //# sourceMappingURL=listProjects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listProjects.d.ts","names":[],"sources":["../../src/listProjects.ts"],"sourcesContent":[],"mappings":";;;KAIY,0BAAA,GAA6B;;EAA7B,QAAA,CAAA,EAAA,OAAA;AAKZ,CAAA;cAAa,gCACD,+BAA0B"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","names":[],"sources":["../../src/pull.ts"],"sourcesContent":[],"mappings":";;;KAmBK,WAAA;;EAAA,mBAAW,CAAA,EAAA,MAGE;EAcL,aA8OZ,CAAA,EA5PiB,uBAcwC;;;;;;cAA7C,iBAAwB,gBAAc"}
1
+ {"version":3,"file":"pull.d.ts","names":[],"sources":["../../src/pull.ts"],"sourcesContent":[],"mappings":";;;KAmBK,WAAA;;EAAA,mBAAW,CAAA,EAAA,MAGE;EAcL,aA8OZ,CAAA,EA5PiB,uBAciC;;;;;;cAAtC,iBAAwB,gBAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"pushConfig.d.ts","names":[],"sources":["../../src/pushConfig.ts"],"sourcesContent":[],"mappings":";;;KAQK,WAAA;kBACa;AAJQ,CAAA;AAOb,cAAA,UAA8B,EAAA,CAAA,OAAW,CAAA,EAAX,WAAW,EAAA,GAAA,OAAA,CAAA,IAAA,CAAA"}
1
+ {"version":3,"file":"pushConfig.d.ts","names":[],"sources":["../../src/pushConfig.ts"],"sourcesContent":[],"mappings":";;;KAQK,WAAA;kBACa;AAJQ,CAAA;AAOb,cAAA,UAA8B,EAAA,CAAA,OAAW,CAAX,EAAA,WAAW,EAAA,GAAA,OAAA,CAAA,IAAA,CAAA"}
@@ -3,7 +3,7 @@ import { GetConfigurationOptions } from "@intlayer/config";
3
3
  import { AIOptions } from "@intlayer/api";
4
4
  import { ListGitFilesOptions } from "@intlayer/chokidar";
5
5
 
6
- //#region src/reviewDoc.d.ts
6
+ //#region src/reviewDoc/reviewDoc.d.ts
7
7
  type ReviewDocOptions = {
8
8
  docPattern: string[];
9
9
  locales: Locale[];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewDoc.d.ts","names":[],"sources":["../../../src/reviewDoc/reviewDoc.ts"],"sourcesContent":[],"mappings":";;;;;;KA0BK,gBAAA;;EAAA,OAAA,EAEM,MAFN,EAAA;EAEM,mBAAA,EAAA,MAAA,EAAA;EAEG,UAAA,EAAA,MAAA;EACA,SAAA,CAAA,EAAA,SAAA;EAEI,2BAAA,CAAA,EAAA,MAAA;EAEyB,aAAA,CAAA,EAFzB,uBAEyB;EACD,kBAAA,CAAA,EAAA,MAAA;EAE3B,oBAAA,CAAA,EAAA,MAAA,GAAA,MAAA,GAH4B,IAG5B;EAAmB,mBAAA,CAAA,EAAA,MAAA,GAAA,MAAA,GAFQ,IAER;EAOrB,YAqIZ,CAAA,EAAA,OAAA;EArI+B,UAAA,CAAA,EAPjB,mBAOiB;CAAA;;;;;AAAA,cAAnB,SAAmB,EAAA,CAAA;EAAA,UAAA;EAAA,OAAA;EAAA,mBAAA;EAAA,UAAA;EAAA,SAAA;EAAA,2BAAA;EAAA,aAAA;EAAA,kBAAA;EAAA,oBAAA;EAAA,mBAAA;EAAA,YAAA;EAAA;AAAA,CAAA,EAa7B,gBAb6B,EAAA,GAab,OAba,CAAA,IAAA,CAAA"}
@@ -1,10 +1,10 @@
1
- import { AIClient } from "./utils/setupAI.js";
1
+ import { AIClient } from "../utils/setupAI.js";
2
2
  import { Locale } from "@intlayer/types";
3
3
  import { GetConfigurationOptions } from "@intlayer/config";
4
4
  import { AIOptions } from "@intlayer/api";
5
5
  import { AIConfig } from "@intlayer/ai";
6
6
 
7
- //#region src/reviewDocBlockAware.d.ts
7
+ //#region src/reviewDoc/reviewDocBlockAware.d.ts
8
8
 
9
9
  /**
10
10
  * Review a file using block-aware alignment.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewDocBlockAware.d.ts","names":[],"sources":["../../../src/reviewDoc/reviewDocBlockAware.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAqCA;;;;;;;AAUqB,cAVR,oBAUQ,EAAA,CAAA,YAAA,EAAA,MAAA,EAAA,cAAA,EAAA,MAAA,EAAA,MAAA,EAPX,MAOW,EAAA,UAAA,EANP,MAMO,EAAA,SAAA,CAAA,EALP,SAKO,EAAA,aAAA,CAAA,EAJH,uBAIG,EAAA,kBAAA,CAAA,EAAA,MAAA,EAAA,YAAA,CAAA,EAAA,MAAA,EAAA,EAAA,QAAA,CAAA,EADR,QACQ,EAAA,QAAA,CAAA,EAAR,QAAQ,EAAA,GAAA,OAAA,CAAA,IAAA,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { ErrorState, FlushStrategy, LimitFunction, TranslateDocOptions, TranslateFileOptions } from "./types.js";
2
+ import { translateDoc } from "./translateDoc.js";
3
+ import { translateFile } from "./translateFile.js";
4
+ import { sanitizeChunk, validateTranslation } from "./validation.js";
5
+ export { ErrorState, FlushStrategy, LimitFunction, TranslateDocOptions, TranslateFileOptions, sanitizeChunk, translateDoc, translateFile, validateTranslation };
@@ -0,0 +1,21 @@
1
+ import { TranslateDocOptions } from "./types.js";
2
+
3
+ //#region src/translateDoc/translateDoc.d.ts
4
+ declare const translateDoc: ({
5
+ docPattern,
6
+ locales,
7
+ excludedGlobPattern,
8
+ baseLocale,
9
+ aiOptions,
10
+ nbSimultaneousFileProcessed,
11
+ configOptions,
12
+ customInstructions,
13
+ skipIfModifiedBefore,
14
+ skipIfModifiedAfter,
15
+ skipIfExists,
16
+ gitOptions,
17
+ flushStrategy
18
+ }: TranslateDocOptions) => Promise<void>;
19
+ //#endregion
20
+ export { translateDoc };
21
+ //# sourceMappingURL=translateDoc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateDoc.d.ts","names":[],"sources":["../../../src/translateDoc/translateDoc.ts"],"sourcesContent":[],"mappings":";;;cAmBa;;;;;;;;;;;;;;GAcV,wBAAmB"}
@@ -0,0 +1,21 @@
1
+ import { TranslateFileOptions } from "./types.js";
2
+
3
+ //#region src/translateDoc/translateFile.d.ts
4
+ declare const translateFile: ({
5
+ baseFilePath,
6
+ outputFilePath,
7
+ locale,
8
+ baseLocale,
9
+ configuration,
10
+ errorState,
11
+ aiOptions,
12
+ customInstructions,
13
+ aiClient,
14
+ aiConfig,
15
+ flushStrategy,
16
+ onChunkReceive,
17
+ limit
18
+ }: TranslateFileOptions) => Promise<string | null>;
19
+ //#endregion
20
+ export { translateFile };
21
+ //# sourceMappingURL=translateFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateFile.d.ts","names":[],"sources":["../../../src/translateDoc/translateFile.ts"],"sourcesContent":[],"mappings":";;;cAoBa;;;;;;;;;;;;;;GAcV,yBAAuB"}