@intlpullhq/cli 0.1.6 → 0.1.7

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 (3) hide show
  1. package/README.md +48 -0
  2. package/dist/index.js +680 -922
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -918,8 +918,8 @@ import { useState as useState6, useEffect as useEffect5 } from "react";
918
918
  import { Box as Box9, Text as Text10, useApp as useApp2 } from "ink";
919
919
  import SelectInput2 from "ink-select-input";
920
920
  import Spinner3 from "ink-spinner";
921
- import { writeFileSync, mkdirSync, existsSync } from "fs";
922
- import { join, dirname } from "path";
921
+ import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
922
+ import { join as join2, dirname as dirname2 } from "path";
923
923
 
924
924
  // src/commands/pull/api.ts
925
925
  async function fetchProjects2(apiUrl, apiKey) {
@@ -1080,16 +1080,23 @@ async function fetchTranslationsParallel(projectId, apiUrl, apiKey, options) {
1080
1080
  })
1081
1081
  );
1082
1082
  const bundle = {};
1083
+ const namespacedBundle = {};
1083
1084
  for (const result of results) {
1084
1085
  if (!bundle[result.language]) {
1085
1086
  bundle[result.language] = {};
1086
1087
  }
1087
1088
  Object.assign(bundle[result.language], result.translations);
1089
+ if (!namespacedBundle[result.language]) {
1090
+ namespacedBundle[result.language] = {};
1091
+ }
1092
+ namespacedBundle[result.language][result.namespace] = result.translations;
1088
1093
  }
1089
1094
  return {
1090
1095
  bundle,
1096
+ namespacedBundle,
1091
1097
  version: projectData.current_version || "1.0.0",
1092
- namespaceCount: namespaces.length
1098
+ namespaceCount: namespaces.length,
1099
+ namespaces
1093
1100
  };
1094
1101
  }
1095
1102
  async function fetchProjectInfo(projectId, apiUrl, apiKey) {
@@ -1190,6 +1197,51 @@ function MultiSelect({ items, selected, onToggle, onSubmit, isActive = true }) {
1190
1197
  ] });
1191
1198
  }
1192
1199
 
1200
+ // src/lib/output-resolver.ts
1201
+ import { join, dirname, extname } from "path";
1202
+ import { mkdirSync, existsSync } from "fs";
1203
+ function hasNamespacePlaceholder(pattern) {
1204
+ return pattern.includes("[namespace]") || pattern.includes("{namespace}");
1205
+ }
1206
+ function getFormatExtension(format) {
1207
+ switch (format) {
1208
+ case "yaml":
1209
+ case "yml":
1210
+ return ".yaml";
1211
+ case "ts":
1212
+ case "typescript":
1213
+ return ".ts";
1214
+ case "json":
1215
+ default:
1216
+ return ".json";
1217
+ }
1218
+ }
1219
+ function resolveOutputPath(pattern, options) {
1220
+ let resolved = pattern;
1221
+ resolved = resolved.replace(/\[locale\]/g, options.locale);
1222
+ resolved = resolved.replace(/\{locale\}/g, options.locale);
1223
+ if (options.namespace) {
1224
+ resolved = resolved.replace(/\[namespace\]/g, options.namespace);
1225
+ resolved = resolved.replace(/\{namespace\}/g, options.namespace);
1226
+ }
1227
+ if (options.format) {
1228
+ const currentExt = extname(resolved);
1229
+ const targetExt = getFormatExtension(options.format);
1230
+ if (currentExt && currentExt !== targetExt) {
1231
+ resolved = resolved.slice(0, -currentExt.length) + targetExt;
1232
+ }
1233
+ }
1234
+ return {
1235
+ path: resolved,
1236
+ dir: dirname(resolved)
1237
+ };
1238
+ }
1239
+ function ensureDir(dir) {
1240
+ if (!existsSync(dir)) {
1241
+ mkdirSync(dir, { recursive: true });
1242
+ }
1243
+ }
1244
+
1193
1245
  // src/commands/pull/components/interactive-pull.tsx
1194
1246
  import { Fragment, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1195
1247
  function InteractivePull({ initialOptions }) {
@@ -1240,43 +1292,87 @@ function InteractivePull({ initialOptions }) {
1240
1292
  const apiUrl = globalConfig.apiUrl || "https://api.intlpull.com";
1241
1293
  const apiKey = resolved?.key;
1242
1294
  setPullState((s) => ({ ...s, message: "Fetching translations..." }));
1243
- const { bundle, version } = await fetchTranslations(
1295
+ const result = await fetchTranslationsParallel(
1244
1296
  projectId,
1245
1297
  apiUrl,
1246
1298
  apiKey,
1247
1299
  {
1248
1300
  languages: state.selectedLanguages.length > 0 ? state.selectedLanguages : void 0,
1249
- platform: state.selectedPlatform
1301
+ platform: state.selectedPlatform,
1302
+ branch: state.selectedBranch,
1303
+ onProgress: (completed, total) => {
1304
+ setPullState((s) => ({
1305
+ ...s,
1306
+ message: `Fetching translations (${completed}/${total})...`
1307
+ }));
1308
+ }
1250
1309
  }
1251
1310
  );
1311
+ const { bundle, namespacedBundle, version, namespaces } = result;
1252
1312
  const locales = state.selectedLanguages.length > 0 ? state.selectedLanguages : Object.keys(bundle);
1253
1313
  if (locales.length === 0) {
1254
1314
  throw new Error("No translations found for this project.");
1255
1315
  }
1256
- const outputDir = initialOptions.output || projectConfig?.outputDir || "./messages";
1316
+ const outputPattern = initialOptions.output || projectConfig?.output || (projectConfig?.outputDir ? `${projectConfig.outputDir}/[locale].json` : "./messages/[locale].json");
1257
1317
  const format = state.selectedFormat;
1258
1318
  const ext = getFileExtension(format);
1259
- setPullState((s) => ({
1260
- ...s,
1261
- message: `Writing ${locales.length} translation files...`
1262
- }));
1319
+ const useNamespaces = hasNamespacePlaceholder(outputPattern) && namespacedBundle && namespaces.length > 0;
1320
+ if (useNamespaces) {
1321
+ setPullState((s) => ({
1322
+ ...s,
1323
+ message: `Writing ${locales.length} \xD7 ${namespaces.length} translation files...`
1324
+ }));
1325
+ } else {
1326
+ setPullState((s) => ({
1327
+ ...s,
1328
+ message: `Writing ${locales.length} translation files...`
1329
+ }));
1330
+ }
1263
1331
  const writtenFiles = [];
1264
1332
  let totalKeyCount = 0;
1265
- for (const locale of locales) {
1266
- if (!bundle[locale]) continue;
1267
- const outputPath = join(outputDir, `${locale}${ext}`);
1268
- const dir = dirname(outputPath);
1269
- if (!existsSync(dir)) {
1270
- mkdirSync(dir, { recursive: true });
1333
+ if (useNamespaces && namespacedBundle) {
1334
+ for (const locale of locales) {
1335
+ if (!namespacedBundle[locale]) continue;
1336
+ for (const namespace of namespaces) {
1337
+ const translations = namespacedBundle[locale][namespace];
1338
+ if (!translations || Object.keys(translations).length === 0) continue;
1339
+ const { path: outputPath, dir } = resolveOutputPath(outputPattern, {
1340
+ locale,
1341
+ namespace,
1342
+ format
1343
+ });
1344
+ ensureDir(dir);
1345
+ const content = formatTranslations(translations, format, locale);
1346
+ writeFileSync(outputPath, content);
1347
+ writtenFiles.push(outputPath);
1348
+ totalKeyCount += Object.keys(translations).length;
1349
+ }
1350
+ }
1351
+ } else {
1352
+ for (const locale of locales) {
1353
+ if (!bundle[locale]) continue;
1354
+ let outputPath;
1355
+ if (outputPattern.includes("[locale]") || outputPattern.includes("{locale}")) {
1356
+ const resolved2 = resolveOutputPath(outputPattern, { locale, format });
1357
+ outputPath = resolved2.path;
1358
+ ensureDir(resolved2.dir);
1359
+ } else {
1360
+ outputPath = join2(outputPattern, `${locale}${ext}`);
1361
+ const dir = dirname2(outputPath);
1362
+ if (!existsSync2(dir)) {
1363
+ mkdirSync2(dir, { recursive: true });
1364
+ }
1365
+ }
1366
+ const content = formatTranslations(bundle[locale], format, locale);
1367
+ writeFileSync(outputPath, content);
1368
+ writtenFiles.push(outputPath);
1369
+ totalKeyCount += Object.keys(bundle[locale]).length;
1271
1370
  }
1272
- const content = formatTranslations(bundle[locale], format, locale);
1273
- writeFileSync(outputPath, content);
1274
- writtenFiles.push(outputPath);
1275
- totalKeyCount += Object.keys(bundle[locale]).length;
1276
1371
  }
1372
+ const successMessage = useNamespaces ? `Successfully pulled ${locales.length} languages \xD7 ${namespaces.length} namespaces` : "Successfully pulled translations";
1277
1373
  setPullState({
1278
1374
  status: "success",
1279
- message: "Successfully pulled translations",
1375
+ message: successMessage,
1280
1376
  files: writtenFiles,
1281
1377
  details: {
1282
1378
  version,
@@ -1545,8 +1641,8 @@ function InteractivePull({ initialOptions }) {
1545
1641
  import { useState as useState7, useEffect as useEffect6 } from "react";
1546
1642
  import { Box as Box10, Text as Text11 } from "ink";
1547
1643
  import Spinner4 from "ink-spinner";
1548
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
1549
- import { join as join2, dirname as dirname2 } from "path";
1644
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync3 } from "fs";
1645
+ import { join as join3, dirname as dirname3 } from "path";
1550
1646
 
1551
1647
  // src/lib/frameworks.ts
1552
1648
  var LIBRARIES2 = {
@@ -1559,10 +1655,13 @@ var LIBRARIES2 = {
1559
1655
  translationCall: (key, params) => params ? `t('${key}', ${params})` : `t('${key}')`,
1560
1656
  pluralSupport: true,
1561
1657
  defaultOutputDir: "./messages",
1562
- filePattern: "{locale}.json",
1658
+ // next-intl uses flat files by default, but supports namespaced via getMessage()
1659
+ // Users can configure messages/[locale]/[namespace].json if they prefer namespacing
1660
+ filePattern: "[locale].json",
1563
1661
  setupInstructions: [
1564
1662
  "npm install next-intl",
1565
- "Create messages/{locale}.json files",
1663
+ "Create messages/[locale].json files",
1664
+ "Configure src/i18n/request.ts to load from messages/",
1566
1665
  "Add NextIntlClientProvider to layout",
1567
1666
  "Configure next.config.js with createNextIntlPlugin()"
1568
1667
  ]
@@ -1576,10 +1675,13 @@ var LIBRARIES2 = {
1576
1675
  translationCall: (key, params) => params ? `t('${key}', ${params})` : `t('${key}')`,
1577
1676
  pluralSupport: true,
1578
1677
  defaultOutputDir: "./public/locales",
1579
- filePattern: "{locale}/{namespace}.json",
1678
+ // react-i18next with i18next-http-backend expects this structure
1679
+ // IMPORTANT: Must match backend.loadPath in i18n.js config
1680
+ filePattern: "[locale]/[namespace].json",
1580
1681
  setupInstructions: [
1581
- "npm install react-i18next i18next",
1582
- "Create public/locales/{locale}/{namespace}.json files",
1682
+ "npm install react-i18next i18next i18next-http-backend",
1683
+ "Create public/locales/[locale]/[namespace].json files",
1684
+ 'Configure i18n.js with backend.loadPath: "/locales/{{lng}}/{{ns}}.json"',
1583
1685
  "Initialize i18next with i18n.init()",
1584
1686
  "Wrap app with I18nextProvider"
1585
1687
  ]
@@ -1593,11 +1695,11 @@ var LIBRARIES2 = {
1593
1695
  translationCall: (key, params) => params ? `i18next.t('${key}', ${params})` : `i18next.t('${key}')`,
1594
1696
  pluralSupport: true,
1595
1697
  defaultOutputDir: "./locales",
1596
- filePattern: "{locale}/{namespace}.json",
1698
+ filePattern: "[locale]/[namespace].json",
1597
1699
  setupInstructions: [
1598
1700
  "npm install i18next",
1599
- "Create locales/{locale}/{namespace}.json files",
1600
- "Initialize i18next with i18n.init()"
1701
+ "Create locales/[locale]/[namespace].json files",
1702
+ "Initialize i18next with resources or backend loader"
1601
1703
  ]
1602
1704
  },
1603
1705
  "react-intl": {
@@ -1609,10 +1711,11 @@ var LIBRARIES2 = {
1609
1711
  translationCall: (key, params) => params ? `intl.formatMessage({ id: '${key}' }, ${params})` : `intl.formatMessage({ id: '${key}' })`,
1610
1712
  pluralSupport: true,
1611
1713
  defaultOutputDir: "./src/lang",
1612
- filePattern: "{locale}.json",
1714
+ // react-intl typically uses flat files (messages extracted by ID)
1715
+ filePattern: "[locale].json",
1613
1716
  setupInstructions: [
1614
1717
  "npm install react-intl",
1615
- "Create src/lang/{locale}.json files",
1718
+ "Create src/lang/[locale].json files",
1616
1719
  "Wrap app with IntlProvider",
1617
1720
  "Import and pass messages to IntlProvider"
1618
1721
  ]
@@ -1626,10 +1729,11 @@ var LIBRARIES2 = {
1626
1729
  translationCall: (key, params) => params ? `t('${key}', ${params})` : `t('${key}')`,
1627
1730
  pluralSupport: true,
1628
1731
  defaultOutputDir: "./src/locales",
1629
- filePattern: "{locale}.json",
1732
+ // vue-i18n supports both flat and namespaced, defaulting to flat
1733
+ filePattern: "[locale].json",
1630
1734
  setupInstructions: [
1631
1735
  "npm install vue-i18n",
1632
- "Create src/locales/{locale}.json files",
1736
+ "Create src/locales/[locale].json files",
1633
1737
  "Create and configure i18n instance",
1634
1738
  "Use app.use(i18n) in main.js"
1635
1739
  ]
@@ -1643,10 +1747,10 @@ var LIBRARIES2 = {
1643
1747
  translationCall: (key, params) => params ? `$_('${key}', ${params})` : `$_('${key}')`,
1644
1748
  pluralSupport: true,
1645
1749
  defaultOutputDir: "./src/lib/i18n",
1646
- filePattern: "{locale}.json",
1750
+ filePattern: "[locale].json",
1647
1751
  setupInstructions: [
1648
1752
  "npm install svelte-i18n",
1649
- "Create src/lib/i18n/{locale}.json files",
1753
+ "Create src/lib/i18n/[locale].json files",
1650
1754
  "Initialize with init() and register()",
1651
1755
  "Use $_ or $t stores in components"
1652
1756
  ]
@@ -1660,10 +1764,10 @@ var LIBRARIES2 = {
1660
1764
  translationCall: (key, params) => params ? `t('${key}', ${params})` : `t('${key}')`,
1661
1765
  pluralSupport: true,
1662
1766
  defaultOutputDir: "./public/locales",
1663
- filePattern: "{locale}/{namespace}.json",
1767
+ filePattern: "[locale]/[namespace].json",
1664
1768
  setupInstructions: [
1665
1769
  "npx astro add astro-i18next",
1666
- "Create public/locales/{locale}/{namespace}.json files",
1770
+ "Create public/locales/[locale]/[namespace].json files",
1667
1771
  "Configure astro-i18next in astro.config.mjs"
1668
1772
  ]
1669
1773
  }
@@ -1742,8 +1846,10 @@ Or use a project-scoped API key for automatic selection.`
1742
1846
  const branchDisplay = branch && branch !== "main" ? ` from branch '${branch}'` : "";
1743
1847
  setState((s) => ({ ...s, status: "downloading", message: `Downloading ${targetLanguages.length} languages${branchDisplay}...` }));
1744
1848
  let bundle;
1849
+ let namespacedBundle;
1745
1850
  let version;
1746
1851
  let namespaceCount = 0;
1852
+ let namespaces = [];
1747
1853
  if (useParallel) {
1748
1854
  const result = await fetchTranslationsParallel(
1749
1855
  projectId,
@@ -1762,8 +1868,10 @@ Or use a project-scoped API key for automatic selection.`
1762
1868
  }
1763
1869
  );
1764
1870
  bundle = result.bundle;
1871
+ namespacedBundle = result.namespacedBundle;
1765
1872
  version = result.version;
1766
1873
  namespaceCount = result.namespaceCount;
1874
+ namespaces = result.namespaces;
1767
1875
  const hasContent = Object.values(bundle).some(
1768
1876
  (langBundle) => Object.keys(langBundle).length > 0
1769
1877
  );
@@ -1776,6 +1884,8 @@ Or use a project-scoped API key for automatic selection.`
1776
1884
  });
1777
1885
  bundle = exportResult.bundle;
1778
1886
  version = exportResult.version;
1887
+ namespacedBundle = void 0;
1888
+ namespaces = [];
1779
1889
  }
1780
1890
  } else {
1781
1891
  const result = await fetchTranslations(projectId, apiUrl, apiKey, {
@@ -1791,23 +1901,46 @@ Or use a project-scoped API key for automatic selection.`
1791
1901
  const writtenFiles = [];
1792
1902
  let totalKeyCount = 0;
1793
1903
  const filePattern = libraryConfig?.filePattern || "{locale}.json";
1794
- const useNamespaceFolders = filePattern.includes("{namespace}");
1795
- for (const locale of targetLanguages) {
1796
- if (!bundle[locale]) continue;
1797
- let outputPath;
1798
- if (useNamespaceFolders) {
1799
- outputPath = join2(outputDir, locale, `common${ext}`);
1800
- } else {
1801
- outputPath = join2(outputDir, `${locale}${ext}`);
1904
+ const useNamespaceFiles = hasNamespacePlaceholder(filePattern) && namespacedBundle && namespaces.length > 0;
1905
+ const outputPattern = filePattern.startsWith("./") ? filePattern : join3(outputDir, filePattern);
1906
+ if (useNamespaceFiles && namespacedBundle) {
1907
+ for (const locale of targetLanguages) {
1908
+ if (!namespacedBundle[locale]) continue;
1909
+ for (const namespace of namespaces) {
1910
+ const translations = namespacedBundle[locale][namespace];
1911
+ if (!translations || Object.keys(translations).length === 0) continue;
1912
+ const { path: outputPath, dir } = resolveOutputPath(outputPattern, {
1913
+ locale,
1914
+ namespace,
1915
+ format
1916
+ });
1917
+ ensureDir(dir);
1918
+ const content = formatTranslations(translations, format, locale);
1919
+ writeFileSync2(outputPath, content);
1920
+ writtenFiles.push(outputPath);
1921
+ totalKeyCount += Object.keys(translations).length;
1922
+ }
1802
1923
  }
1803
- const dir = dirname2(outputPath);
1804
- if (!existsSync2(dir)) {
1805
- mkdirSync2(dir, { recursive: true });
1924
+ } else {
1925
+ for (const locale of targetLanguages) {
1926
+ if (!bundle[locale]) continue;
1927
+ let outputPath;
1928
+ if (filePattern.includes("{locale}") || filePattern.includes("[locale]")) {
1929
+ const { path: path4, dir } = resolveOutputPath(outputPattern, { locale, format });
1930
+ outputPath = path4;
1931
+ ensureDir(dir);
1932
+ } else {
1933
+ outputPath = join3(outputDir, `${locale}${ext}`);
1934
+ const dir = dirname3(outputPath);
1935
+ if (!existsSync3(dir)) {
1936
+ mkdirSync3(dir, { recursive: true });
1937
+ }
1938
+ }
1939
+ const content = formatTranslations(bundle[locale], format, locale);
1940
+ writeFileSync2(outputPath, content);
1941
+ writtenFiles.push(outputPath);
1942
+ totalKeyCount += Object.keys(bundle[locale]).length;
1806
1943
  }
1807
- const content = formatTranslations(bundle[locale], format, locale);
1808
- writeFileSync2(outputPath, content);
1809
- writtenFiles.push(outputPath);
1810
- totalKeyCount += Object.keys(bundle[locale]).length;
1811
1944
  }
1812
1945
  if (!projectConfig && projectId) {
1813
1946
  const newConfig = {
@@ -1816,13 +1949,14 @@ Or use a project-scoped API key for automatic selection.`
1816
1949
  library: detected.library,
1817
1950
  outputDir,
1818
1951
  sourceLanguage: projectInfo.languages[0] || "en",
1819
- namespaces: ["common"]
1952
+ namespaces: namespaces.length > 0 ? namespaces : ["common"]
1820
1953
  };
1821
1954
  saveProjectConfig(newConfig);
1822
1955
  }
1956
+ const successMessage = useNamespaceFiles ? `Downloaded ${targetLanguages.length} languages \xD7 ${namespaceCount} namespaces` : useParallel ? `Downloaded ${targetLanguages.length} languages (${namespaceCount} namespaces merged)` : `Downloaded ${targetLanguages.length} languages`;
1823
1957
  setState({
1824
1958
  status: "success",
1825
- message: useParallel ? `Downloaded ${targetLanguages.length} languages (${namespaceCount} namespaces)` : `Downloaded ${targetLanguages.length} languages`,
1959
+ message: successMessage,
1826
1960
  project: projectInfo,
1827
1961
  framework: detected,
1828
1962
  outputDir,
@@ -1925,8 +2059,8 @@ function runPull(options) {
1925
2059
  import React8 from "react";
1926
2060
  import { render as render5, Box as Box11, Text as Text12, useInput as useInput3 } from "ink";
1927
2061
  import Spinner5 from "ink-spinner";
1928
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
1929
- import { join as join4, basename as basename2, extname as extname2 } from "path";
2062
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
2063
+ import { join as join5, basename as basename2, extname as extname3 } from "path";
1930
2064
 
1931
2065
  // src/lib/languages.ts
1932
2066
  var LANGUAGES = [
@@ -2097,8 +2231,8 @@ function formatLanguageDisplay(code, includeFlag = true) {
2097
2231
  }
2098
2232
 
2099
2233
  // src/lib/discovery.ts
2100
- import { existsSync as existsSync3, readdirSync, statSync, readFileSync } from "fs";
2101
- import { join as join3, basename, extname, dirname as dirname3, relative } from "path";
2234
+ import { existsSync as existsSync4, readdirSync, statSync, readFileSync } from "fs";
2235
+ import { join as join4, basename, extname as extname2, dirname as dirname4, relative } from "path";
2102
2236
  import yaml from "js-yaml";
2103
2237
  var COMMON_PATHS = [
2104
2238
  // next-intl
@@ -2133,7 +2267,7 @@ function isLikelyLanguageCode(str) {
2133
2267
  return false;
2134
2268
  }
2135
2269
  function isNamespaceFile(filename) {
2136
- const name = basename(filename, extname(filename));
2270
+ const name = basename(filename, extname2(filename));
2137
2271
  const commonNamespaces = [
2138
2272
  "common",
2139
2273
  "translation",
@@ -2183,7 +2317,7 @@ function countKeys(obj) {
2183
2317
  return count;
2184
2318
  }
2185
2319
  function parseTranslationFile(filePath) {
2186
- const ext = extname(filePath).toLowerCase();
2320
+ const ext = extname2(filePath).toLowerCase();
2187
2321
  try {
2188
2322
  if (ext === ".json") {
2189
2323
  const content = JSON.parse(readFileSync(filePath, "utf-8"));
@@ -2206,7 +2340,7 @@ function parseTranslationFile(filePath) {
2206
2340
  }
2207
2341
  function detectLanguageFromPath(filePath) {
2208
2342
  const parts = filePath.split(/[\/\\]/);
2209
- const fileName = basename(filePath, extname(filePath));
2343
+ const fileName = basename(filePath, extname2(filePath));
2210
2344
  if (isLikelyLanguageCode(fileName)) {
2211
2345
  return normalizeLanguageCode(fileName);
2212
2346
  }
@@ -2220,11 +2354,11 @@ function detectLanguageFromPath(filePath) {
2220
2354
  }
2221
2355
  function scanDirectory(dir, projectRoot, depth = 0, maxDepth = 3) {
2222
2356
  const files = [];
2223
- if (depth > maxDepth || !existsSync3(dir)) return files;
2357
+ if (depth > maxDepth || !existsSync4(dir)) return files;
2224
2358
  try {
2225
2359
  const entries = readdirSync(dir);
2226
2360
  for (const entry of entries) {
2227
- const fullPath = join3(dir, entry);
2361
+ const fullPath = join4(dir, entry);
2228
2362
  const relativePath = relative(projectRoot, fullPath).replace(/\\/g, "/");
2229
2363
  try {
2230
2364
  const stat = statSync(fullPath);
@@ -2234,7 +2368,7 @@ function scanDirectory(dir, projectRoot, depth = 0, maxDepth = 3) {
2234
2368
  }
2235
2369
  files.push(...scanDirectory(fullPath, projectRoot, depth + 1, maxDepth));
2236
2370
  } else if (stat.isFile()) {
2237
- const ext = extname(entry).toLowerCase();
2371
+ const ext = extname2(entry).toLowerCase();
2238
2372
  if (![".json", ".yaml", ".yml", ".ts", ".js"].includes(ext)) continue;
2239
2373
  if (entry.includes("config") || entry.includes("tsconfig")) continue;
2240
2374
  const parsed = parseTranslationFile(fullPath);
@@ -2242,7 +2376,7 @@ function scanDirectory(dir, projectRoot, depth = 0, maxDepth = 3) {
2242
2376
  const language = detectLanguageFromPath(fullPath);
2243
2377
  if (!language) continue;
2244
2378
  let namespace;
2245
- const parentDir = basename(dirname3(fullPath));
2379
+ const parentDir = basename(dirname4(fullPath));
2246
2380
  const fileName = basename(entry, ext);
2247
2381
  if (isLikelyLanguageCode(parentDir)) {
2248
2382
  namespace = fileName;
@@ -2282,7 +2416,7 @@ function determineStructure(files, baseDir) {
2282
2416
  return maxFilesPerLang > 1 ? "nested" : "flat";
2283
2417
  }
2284
2418
  const hasNamespaceInFilename = files.some((f) => {
2285
- const name = basename(f.path, extname(f.path));
2419
+ const name = basename(f.path, extname2(f.path));
2286
2420
  return name.includes(".") && !isLikelyLanguageCode(name);
2287
2421
  });
2288
2422
  if (hasNamespaceInFilename) return "namespace-based";
@@ -2345,13 +2479,13 @@ function discoverTranslationFiles(projectRoot = process.cwd()) {
2345
2479
  const framework = detectFramework(projectRoot);
2346
2480
  let files = [];
2347
2481
  let baseDir = "";
2348
- const configPath = join3(projectRoot, ".intlpull.json");
2349
- if (existsSync3(configPath)) {
2482
+ const configPath = join4(projectRoot, ".intlpull.json");
2483
+ if (existsSync4(configPath)) {
2350
2484
  try {
2351
2485
  const config = JSON.parse(readFileSync(configPath, "utf-8"));
2352
2486
  if (config.outputDir) {
2353
- const configuredDir = join3(projectRoot, config.outputDir);
2354
- if (existsSync3(configuredDir)) {
2487
+ const configuredDir = join4(projectRoot, config.outputDir);
2488
+ if (existsSync4(configuredDir)) {
2355
2489
  files = scanDirectory(configuredDir, projectRoot);
2356
2490
  if (files.length > 0) {
2357
2491
  baseDir = configuredDir;
@@ -2364,8 +2498,8 @@ function discoverTranslationFiles(projectRoot = process.cwd()) {
2364
2498
  }
2365
2499
  if (files.length === 0) {
2366
2500
  for (const commonPath of COMMON_PATHS) {
2367
- const dir = join3(projectRoot, commonPath);
2368
- if (existsSync3(dir)) {
2501
+ const dir = join4(projectRoot, commonPath);
2502
+ if (existsSync4(dir)) {
2369
2503
  const foundFiles = scanDirectory(dir, projectRoot);
2370
2504
  if (foundFiles.length > 0) {
2371
2505
  files = foundFiles;
@@ -2377,11 +2511,11 @@ function discoverTranslationFiles(projectRoot = process.cwd()) {
2377
2511
  }
2378
2512
  }
2379
2513
  if (files.length === 0) {
2380
- const srcDir = join3(projectRoot, "src");
2381
- if (existsSync3(srcDir)) {
2514
+ const srcDir = join4(projectRoot, "src");
2515
+ if (existsSync4(srcDir)) {
2382
2516
  files = scanDirectory(srcDir, projectRoot, 0, 4);
2383
2517
  if (files.length > 0) {
2384
- const dirs = new Set(files.map((f) => dirname3(f.path)));
2518
+ const dirs = new Set(files.map((f) => dirname4(f.path)));
2385
2519
  baseDir = dirs.size === 1 ? [...dirs][0] : srcDir;
2386
2520
  indicators.push("Found translation files in src/");
2387
2521
  }
@@ -2473,7 +2607,7 @@ function readSourceTranslationsByNamespace(projectRoot = process.cwd(), sourceLa
2473
2607
  const flattened = flattenTranslations(content);
2474
2608
  const keyCount = Object.keys(flattened).length;
2475
2609
  if (keyCount > 0) {
2476
- const fileNameWithoutExt = basename(file.path, extname(file.path));
2610
+ const fileNameWithoutExt = basename(file.path, extname2(file.path));
2477
2611
  const namespace = file.namespace || (isLikelyLanguageCode(fileNameWithoutExt) ? "common" : fileNameWithoutExt);
2478
2612
  namespaces.push({
2479
2613
  namespace,
@@ -2520,7 +2654,7 @@ function readAllTranslationsByLanguage(projectRoot = process.cwd()) {
2520
2654
  const flattened = flattenTranslations(content);
2521
2655
  const keyCount = Object.keys(flattened).length;
2522
2656
  if (keyCount > 0) {
2523
- const fileNameWithoutExt = basename(file.path, extname(file.path));
2657
+ const fileNameWithoutExt = basename(file.path, extname2(file.path));
2524
2658
  const namespace = file.namespace || (isLikelyLanguageCode(fileNameWithoutExt) ? "common" : fileNameWithoutExt);
2525
2659
  namespaces.push({
2526
2660
  namespace,
@@ -2714,8 +2848,8 @@ To create this branch, go to the IntlPull dashboard or use: npx @intlpullhq/cli
2714
2848
  status: "reading",
2715
2849
  message: `Reading ${options.file}...`
2716
2850
  }));
2717
- const filePath = join4(cwd, options.file);
2718
- if (!existsSync4(filePath)) {
2851
+ const filePath = join5(cwd, options.file);
2852
+ if (!existsSync5(filePath)) {
2719
2853
  setState((prev) => ({
2720
2854
  ...prev,
2721
2855
  status: "error",
@@ -2726,7 +2860,7 @@ To create this branch, go to the IntlPull dashboard or use: npx @intlpullhq/cli
2726
2860
  try {
2727
2861
  const content = JSON.parse(readFileSync2(filePath, "utf-8"));
2728
2862
  const keys = flattenTranslations(content);
2729
- const namespace = basename2(options.file, extname2(options.file));
2863
+ const namespace = basename2(options.file, extname3(options.file));
2730
2864
  namespaces = [{
2731
2865
  namespace,
2732
2866
  keys,
@@ -3777,9 +3911,9 @@ import { readFileSync as readFileSync3 } from "fs";
3777
3911
 
3778
3912
  // src/commands/import/utils.ts
3779
3913
  import { readdirSync as readdirSync2 } from "fs";
3780
- import { join as join5, basename as basename3, extname as extname3 } from "path";
3914
+ import { join as join6, basename as basename3, extname as extname4 } from "path";
3781
3915
  function detectLanguageFromFilename2(filename) {
3782
- const name = basename3(filename, extname3(filename));
3916
+ const name = basename3(filename, extname4(filename));
3783
3917
  const patterns = [
3784
3918
  /^([a-z]{2}(?:-[A-Z]{2})?)$/i,
3785
3919
  // en, en-US
@@ -3799,7 +3933,7 @@ function detectLanguageFromFilename2(filename) {
3799
3933
  return null;
3800
3934
  }
3801
3935
  function detectFormatFromExtension(filename) {
3802
- const ext = extname3(filename).toLowerCase();
3936
+ const ext = extname4(filename).toLowerCase();
3803
3937
  switch (ext) {
3804
3938
  case ".yaml":
3805
3939
  case ".yml":
@@ -3815,13 +3949,13 @@ function findTranslationFiles(dir, pattern) {
3815
3949
  const entries = readdirSync2(dir, { withFileTypes: true });
3816
3950
  for (const entry of entries) {
3817
3951
  if (entry.isFile()) {
3818
- const ext = extname3(entry.name).toLowerCase();
3952
+ const ext = extname4(entry.name).toLowerCase();
3819
3953
  if ([".json", ".yaml", ".yml"].includes(ext)) {
3820
3954
  if (pattern) {
3821
3955
  const regex = new RegExp(pattern.replace(/\*/g, ".*").replace(/\?/g, "."));
3822
3956
  if (!regex.test(entry.name)) continue;
3823
3957
  }
3824
- const filePath = join5(dir, entry.name);
3958
+ const filePath = join6(dir, entry.name);
3825
3959
  files.push({
3826
3960
  path: filePath,
3827
3961
  name: entry.name,
@@ -3830,7 +3964,7 @@ function findTranslationFiles(dir, pattern) {
3830
3964
  });
3831
3965
  }
3832
3966
  } else if (entry.isDirectory() && entry.name !== "node_modules") {
3833
- const subFiles = findTranslationFiles(join5(dir, entry.name), pattern);
3967
+ const subFiles = findTranslationFiles(join6(dir, entry.name), pattern);
3834
3968
  files.push(...subFiles);
3835
3969
  }
3836
3970
  }
@@ -6625,8 +6759,8 @@ import { render as render9, Box as Box22, Text as Text23, useApp as useApp5, use
6625
6759
  import TextInput2 from "ink-text-input";
6626
6760
  import SelectInput6 from "ink-select-input";
6627
6761
  import Spinner11 from "ink-spinner";
6628
- import { readFileSync as readFileSync5, existsSync as existsSync5, statSync as statSync3, readdirSync as readdirSync3 } from "fs";
6629
- import { join as join6, basename as basename5, extname as extname4, relative as relative2 } from "path";
6762
+ import { readFileSync as readFileSync5, existsSync as existsSync6, statSync as statSync3, readdirSync as readdirSync3 } from "fs";
6763
+ import { join as join7, basename as basename5, extname as extname5, relative as relative2 } from "path";
6630
6764
  import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
6631
6765
  function countKeys2(content) {
6632
6766
  try {
@@ -6659,13 +6793,13 @@ function scanTranslationFiles(dir, pattern) {
6659
6793
  return;
6660
6794
  }
6661
6795
  for (const entry of entries) {
6662
- const fullPath = join6(currentDir, entry.name);
6796
+ const fullPath = join7(currentDir, entry.name);
6663
6797
  if (entry.isDirectory()) {
6664
6798
  if (!["node_modules", ".git", "dist", "build", ".next", ".cache", "coverage"].includes(entry.name)) {
6665
6799
  scan(fullPath);
6666
6800
  }
6667
6801
  } else if (entry.isFile()) {
6668
- const ext = extname4(entry.name).toLowerCase();
6802
+ const ext = extname5(entry.name).toLowerCase();
6669
6803
  if (extensions.includes(ext)) {
6670
6804
  if (pattern && !entry.name.match(new RegExp(pattern.replace(/\*/g, ".*")))) {
6671
6805
  continue;
@@ -6694,7 +6828,7 @@ function scanTranslationFiles(dir, pattern) {
6694
6828
  }
6695
6829
  }
6696
6830
  }
6697
- if (existsSync5(dir) && statSync3(dir).isDirectory()) {
6831
+ if (existsSync6(dir) && statSync3(dir).isDirectory()) {
6698
6832
  scan(dir);
6699
6833
  }
6700
6834
  return files.sort((a, b) => a.language.localeCompare(b.language));
@@ -6799,8 +6933,8 @@ Make sure your files follow naming conventions like:
6799
6933
  }
6800
6934
  if (!options.project) {
6801
6935
  try {
6802
- const pkgPath = join6(process.cwd(), "package.json");
6803
- if (existsSync5(pkgPath)) {
6936
+ const pkgPath = join7(process.cwd(), "package.json");
6937
+ if (existsSync6(pkgPath)) {
6804
6938
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
6805
6939
  if (pkg.name) {
6806
6940
  setProjectName(pkg.name.replace(/^@[^/]+\//, ""));
@@ -7149,403 +7283,36 @@ function runMigrateFiles(path4, options) {
7149
7283
  process.exit(1);
7150
7284
  }
7151
7285
  const targetPath = path4 || process.cwd();
7152
- if (!existsSync5(targetPath)) {
7286
+ if (!existsSync6(targetPath)) {
7153
7287
  console.error(`Path not found: ${targetPath}`);
7154
7288
  process.exit(1);
7155
7289
  }
7156
7290
  render9(/* @__PURE__ */ jsx25(MigrationUI, { options, path: targetPath }));
7157
7291
  }
7158
7292
 
7159
- // src/commands/compare.tsx
7160
- import { useState as useState14, useEffect as useEffect11 } from "react";
7161
- import { render as render10, Box as Box23, Text as Text24 } from "ink";
7162
- import Spinner12 from "ink-spinner";
7163
- import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
7164
- var COMPETITOR_PRICING = {
7165
- lokalise: {
7166
- name: "Lokalise",
7167
- tiers: [
7168
- { name: "Start", price: 120, keys: 2e3, users: 5, features: ["Basic features"] },
7169
- { name: "Essential", price: 450, keys: 1e4, users: 10, features: ["TM", "Glossary"] },
7170
- { name: "Pro", price: 990, keys: 3e4, users: 25, features: ["All features"] },
7171
- { name: "Enterprise", price: 2500, keys: 1e5, users: 50, features: ["SSO", "SLA"] }
7172
- ],
7173
- perKeyPricing: { price: 0.045, unit: 1 },
7174
- notes: [
7175
- "Prices are per month, billed annually",
7176
- "Overage charges apply for additional keys",
7177
- "Enterprise pricing varies"
7178
- ]
7179
- },
7180
- crowdin: {
7181
- name: "Crowdin",
7182
- tiers: [
7183
- { name: "Free", price: 0, keys: 500, users: 1, features: ["1 public project"] },
7184
- { name: "Pro", price: 50, keys: 5e3, users: 3, features: ["Private projects"] },
7185
- { name: "Team", price: 250, keys: 25e3, users: 10, features: ["TM", "Glossary"] },
7186
- { name: "Enterprise", price: 600, keys: 1e5, users: 30, features: ["SSO", "API"] }
7187
- ],
7188
- perKeyPricing: { price: 0.02, unit: 1 },
7189
- notes: [
7190
- "Prices are per month",
7191
- "Free tier for open source",
7192
- "Enterprise has custom pricing"
7193
- ]
7194
- },
7195
- phrase: {
7196
- name: "Phrase",
7197
- tiers: [
7198
- { name: "Starter", price: 75, keys: 1e3, users: 3, features: ["Basic"] },
7199
- { name: "Pro", price: 250, keys: 5e3, users: 10, features: ["TM", "API"] },
7200
- { name: "Business", price: 600, keys: 2e4, users: 25, features: ["Glossary"] },
7201
- { name: "Enterprise", price: 1500, keys: 1e5, users: 100, features: ["SSO", "SLA"] }
7202
- ],
7203
- perKeyPricing: { price: 0.05, unit: 1 },
7204
- notes: [
7205
- "Prices are per month, billed annually",
7206
- "Phrase Strings pricing",
7207
- "Separate products for TMS"
7208
- ]
7209
- }
7210
- };
7211
- var INTLPULL_PRICING = {
7212
- name: "IntlPull",
7213
- tiers: [
7214
- { name: "Free", price: 0, keys: 1e3, users: 2, features: ["In-context editing", "Chrome extension", "CLI", "OTA updates"] },
7215
- { name: "Pro", price: 19, keys: 1e4, users: 5, features: ["All Free features", "TM", "Glossary", "Branching"] },
7216
- { name: "Team", price: 49, keys: 5e4, users: 15, features: ["All Pro features", "Priority support", "Team roles"] },
7217
- { name: "Business", price: 99, keys: 2e5, users: 50, features: ["All Team features", "SSO", "SLA", "Dedicated support"] }
7218
- ],
7219
- notes: [
7220
- "No per-key overage charges",
7221
- "All plans include OTA updates",
7222
- "Developer-first tools included"
7223
- ]
7224
- };
7225
- function calculateCompetitorCost(provider, keys, users) {
7226
- const pricing = COMPETITOR_PRICING[provider];
7227
- if (!pricing) {
7228
- return { tier: "Unknown", monthly: 0, annual: 0 };
7229
- }
7230
- const suitableTier = pricing.tiers.find((t) => t.keys >= keys && t.users >= users) || pricing.tiers[pricing.tiers.length - 1];
7231
- return {
7232
- tier: suitableTier.name,
7233
- monthly: suitableTier.price,
7234
- annual: suitableTier.price * 12
7235
- };
7236
- }
7237
- function calculateIntlPullCost(keys, users) {
7238
- const suitableTier = INTLPULL_PRICING.tiers.find((t) => t.keys >= keys && t.users >= users) || INTLPULL_PRICING.tiers[INTLPULL_PRICING.tiers.length - 1];
7239
- return {
7240
- tier: suitableTier.name,
7241
- monthly: suitableTier.price,
7242
- annual: suitableTier.price * 12
7243
- };
7244
- }
7245
- function formatCurrency(amount) {
7246
- return new Intl.NumberFormat("en-US", {
7247
- style: "currency",
7248
- currency: "USD",
7249
- minimumFractionDigits: 0,
7250
- maximumFractionDigits: 0
7251
- }).format(amount);
7252
- }
7253
- function formatPercent(value) {
7254
- return `${Math.round(value)}%`;
7255
- }
7256
- function CompareDisplay({ options }) {
7257
- const [loading, setLoading] = useState14(true);
7258
- const [result, setResult] = useState14(null);
7259
- const [projectStats, setProjectStats] = useState14(null);
7260
- useEffect11(() => {
7261
- async function loadData() {
7262
- const config = getProjectConfig();
7263
- const resolved = getResolvedApiKey();
7264
- const globalConfig = getGlobalConfig();
7265
- let keys = options.keys || 1e3;
7266
- let languages = options.languages || 2;
7267
- let users = options.users || 5;
7268
- if (resolved?.key && config?.projectId) {
7269
- try {
7270
- const apiUrl = globalConfig.apiUrl || "https://api.intlpull.com";
7271
- const response = await fetch(`${apiUrl}/api/v1/projects/${config.projectId}`, {
7272
- headers: { "X-API-Key": resolved.key }
7273
- });
7274
- if (response.ok) {
7275
- const data = await response.json();
7276
- keys = data.stats?.total_keys || keys;
7277
- languages = data.languages?.length || languages;
7278
- setProjectStats({ keys, languages });
7279
- }
7280
- } catch {
7281
- }
7282
- }
7283
- const provider = options.from || "lokalise";
7284
- const competitorCost = calculateCompetitorCost(provider, keys, users);
7285
- const intlpullCost = calculateIntlPullCost(keys, users);
7286
- const monthlySavings = competitorCost.monthly - intlpullCost.monthly;
7287
- const annualSavings = competitorCost.annual - intlpullCost.annual;
7288
- const percentSavings = competitorCost.monthly > 0 ? monthlySavings / competitorCost.monthly * 100 : 0;
7289
- setResult({
7290
- competitor: {
7291
- name: COMPETITOR_PRICING[provider]?.name || provider,
7292
- tier: competitorCost.tier,
7293
- monthly: competitorCost.monthly,
7294
- annual: competitorCost.annual
7295
- },
7296
- intlpull: intlpullCost,
7297
- savings: {
7298
- monthly: monthlySavings,
7299
- annual: annualSavings,
7300
- percent: percentSavings
7301
- },
7302
- inputs: { keys, languages, users }
7303
- });
7304
- setLoading(false);
7305
- }
7306
- loadData();
7307
- }, [options]);
7308
- if (loading) {
7309
- return /* @__PURE__ */ jsxs24(Box23, { children: [
7310
- /* @__PURE__ */ jsx26(Text24, { color: "cyan", children: /* @__PURE__ */ jsx26(Spinner12, { type: "dots" }) }),
7311
- /* @__PURE__ */ jsx26(Text24, { children: " Calculating cost comparison..." })
7312
- ] });
7313
- }
7314
- if (!result) {
7315
- return /* @__PURE__ */ jsx26(Box23, { children: /* @__PURE__ */ jsx26(Text24, { color: "red", children: "Failed to calculate comparison" }) });
7316
- }
7317
- if (options.json) {
7318
- return /* @__PURE__ */ jsx26(Text24, { children: JSON.stringify(result, null, 2) });
7319
- }
7320
- return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", paddingX: 1, children: [
7321
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7322
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: "cyan", children: "IntlPull" }),
7323
- /* @__PURE__ */ jsx26(Text24, { children: " \u2022 Cost Comparison" })
7324
- ] }),
7325
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, flexDirection: "column", children: [
7326
- /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Your Usage:" }),
7327
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7328
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Keys: " }),
7329
- /* @__PURE__ */ jsx26(Text24, { children: result.inputs.keys.toLocaleString() }),
7330
- projectStats && /* @__PURE__ */ jsx26(Text24, { color: "green", children: " (from project)" })
7331
- ] }),
7332
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7333
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Languages: " }),
7334
- /* @__PURE__ */ jsx26(Text24, { children: result.inputs.languages })
7335
- ] }),
7336
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7337
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Users: " }),
7338
- /* @__PURE__ */ jsx26(Text24, { children: result.inputs.users })
7339
- ] })
7340
- ] }),
7341
- /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, flexDirection: "column", children: /* @__PURE__ */ jsxs24(Box23, { borderStyle: "single", flexDirection: "column", paddingX: 2, paddingY: 1, children: [
7342
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7343
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: "red", children: result.competitor.name }),
7344
- /* @__PURE__ */ jsxs24(Text24, { children: [
7345
- " (",
7346
- result.competitor.tier,
7347
- " plan)"
7348
- ] })
7349
- ] }),
7350
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7351
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Monthly: " }),
7352
- /* @__PURE__ */ jsx26(Text24, { children: formatCurrency(result.competitor.monthly) })
7353
- ] }),
7354
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7355
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Annual: " }),
7356
- /* @__PURE__ */ jsx26(Text24, { children: formatCurrency(result.competitor.annual) })
7357
- ] }),
7358
- /* @__PURE__ */ jsx26(Box23, { marginY: 1, children: /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
7359
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7360
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: "green", children: "IntlPull" }),
7361
- /* @__PURE__ */ jsxs24(Text24, { children: [
7362
- " (",
7363
- result.intlpull.tier,
7364
- " plan)"
7365
- ] })
7366
- ] }),
7367
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7368
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Monthly: " }),
7369
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: formatCurrency(result.intlpull.monthly) })
7370
- ] }),
7371
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7372
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Annual: " }),
7373
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: formatCurrency(result.intlpull.annual) })
7374
- ] })
7375
- ] }) }),
7376
- result.savings.monthly > 0 && /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, flexDirection: "column", children: [
7377
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: "green", children: "\u{1F4B0} Your Savings with IntlPull:" }),
7378
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7379
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Monthly: " }),
7380
- /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: formatCurrency(result.savings.monthly) }),
7381
- /* @__PURE__ */ jsxs24(Text24, { dimColor: true, children: [
7382
- " (",
7383
- formatPercent(result.savings.percent),
7384
- " less)"
7385
- ] })
7386
- ] }),
7387
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, children: [
7388
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Annual: " }),
7389
- /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: formatCurrency(result.savings.annual) })
7390
- ] })
7391
- ] }),
7392
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, flexDirection: "column", children: [
7393
- /* @__PURE__ */ jsx26(Text24, { bold: true, children: "What you get with IntlPull:" }),
7394
- /* @__PURE__ */ jsxs24(Box23, { paddingLeft: 2, flexDirection: "column", children: [
7395
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 In-context editing (Chrome extension)" }),
7396
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 CLI with smart auto-detection" }),
7397
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 OTA updates for mobile apps" }),
7398
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 Git branch integration" }),
7399
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 AI-powered translation" }),
7400
- /* @__PURE__ */ jsx26(Text24, { color: "green", children: "\u2713 No per-key overage charges" })
7401
- ] })
7402
- ] }),
7403
- /* @__PURE__ */ jsxs24(Box23, { marginTop: 1, children: [
7404
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Ready to switch? Run: " }),
7405
- /* @__PURE__ */ jsxs24(Text24, { color: "cyan", children: [
7406
- "npx @intlpullhq/cli migrate from ",
7407
- options.from || "lokalise"
7408
- ] })
7409
- ] })
7410
- ] });
7411
- }
7412
- function CompareAllProviders({ options }) {
7413
- const [loading, setLoading] = useState14(true);
7414
- const [results, setResults] = useState14([]);
7415
- useEffect11(() => {
7416
- const keys = options.keys || 5e3;
7417
- const users = options.users || 5;
7418
- const languages = options.languages || 3;
7419
- const providers = ["lokalise", "crowdin", "phrase"];
7420
- const comparisons = [];
7421
- for (const provider of providers) {
7422
- const competitorCost = calculateCompetitorCost(provider, keys, users);
7423
- const intlpullCost2 = calculateIntlPullCost(keys, users);
7424
- const monthlySavings = competitorCost.monthly - intlpullCost2.monthly;
7425
- const annualSavings = competitorCost.annual - intlpullCost2.annual;
7426
- const percentSavings = competitorCost.monthly > 0 ? monthlySavings / competitorCost.monthly * 100 : 0;
7427
- comparisons.push({
7428
- competitor: {
7429
- name: COMPETITOR_PRICING[provider]?.name || provider,
7430
- tier: competitorCost.tier,
7431
- monthly: competitorCost.monthly,
7432
- annual: competitorCost.annual
7433
- },
7434
- intlpull: intlpullCost2,
7435
- savings: {
7436
- monthly: monthlySavings,
7437
- annual: annualSavings,
7438
- percent: percentSavings
7439
- },
7440
- inputs: { keys, languages, users }
7441
- });
7442
- }
7443
- setResults(comparisons);
7444
- setLoading(false);
7445
- }, [options]);
7446
- if (loading) {
7447
- return /* @__PURE__ */ jsxs24(Box23, { children: [
7448
- /* @__PURE__ */ jsx26(Text24, { color: "cyan", children: /* @__PURE__ */ jsx26(Spinner12, { type: "dots" }) }),
7449
- /* @__PURE__ */ jsx26(Text24, { children: " Calculating cost comparison..." })
7450
- ] });
7451
- }
7452
- if (options.json) {
7453
- return /* @__PURE__ */ jsx26(Text24, { children: JSON.stringify(results, null, 2) });
7454
- }
7455
- const intlpullCost = results[0]?.intlpull;
7456
- return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", paddingX: 1, children: [
7457
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7458
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: "cyan", children: "IntlPull" }),
7459
- /* @__PURE__ */ jsx26(Text24, { children: " \u2022 Cost Comparison" })
7460
- ] }),
7461
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7462
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Comparing for: " }),
7463
- /* @__PURE__ */ jsxs24(Text24, { children: [
7464
- results[0]?.inputs.keys.toLocaleString(),
7465
- " keys, "
7466
- ] }),
7467
- /* @__PURE__ */ jsxs24(Text24, { children: [
7468
- results[0]?.inputs.users,
7469
- " users, "
7470
- ] }),
7471
- /* @__PURE__ */ jsxs24(Text24, { children: [
7472
- results[0]?.inputs.languages,
7473
- " languages"
7474
- ] })
7475
- ] }),
7476
- /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, flexDirection: "column", children: /* @__PURE__ */ jsxs24(Box23, { borderStyle: "single", flexDirection: "column", paddingX: 2, paddingY: 1, children: [
7477
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7478
- /* @__PURE__ */ jsx26(Box23, { width: 15, children: /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Provider" }) }),
7479
- /* @__PURE__ */ jsx26(Box23, { width: 10, children: /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Plan" }) }),
7480
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Monthly" }) }),
7481
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Annual" }) }),
7482
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { bold: true, children: "Savings" }) })
7483
- ] }),
7484
- results.map((r, i) => /* @__PURE__ */ jsxs24(Box23, { children: [
7485
- /* @__PURE__ */ jsx26(Box23, { width: 15, children: /* @__PURE__ */ jsx26(Text24, { color: "red", children: r.competitor.name }) }),
7486
- /* @__PURE__ */ jsx26(Box23, { width: 10, children: /* @__PURE__ */ jsx26(Text24, { children: r.competitor.tier }) }),
7487
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { children: formatCurrency(r.competitor.monthly) }) }),
7488
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { children: formatCurrency(r.competitor.annual) }) }),
7489
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { color: "green", children: r.savings.monthly > 0 ? formatPercent(r.savings.percent) : "-" }) })
7490
- ] }, i)),
7491
- /* @__PURE__ */ jsx26(Box23, { marginY: 1, children: /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
7492
- /* @__PURE__ */ jsxs24(Box23, { children: [
7493
- /* @__PURE__ */ jsx26(Box23, { width: 15, children: /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: "IntlPull" }) }),
7494
- /* @__PURE__ */ jsx26(Box23, { width: 10, children: /* @__PURE__ */ jsx26(Text24, { children: intlpullCost?.tier }) }),
7495
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: formatCurrency(intlpullCost?.monthly || 0) }) }),
7496
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: formatCurrency(intlpullCost?.annual || 0) }) }),
7497
- /* @__PURE__ */ jsx26(Box23, { width: 12, children: /* @__PURE__ */ jsx26(Text24, { color: "green", bold: true, children: "Best" }) })
7498
- ] })
7499
- ] }) }),
7500
- /* @__PURE__ */ jsxs24(Box23, { marginBottom: 1, children: [
7501
- /* @__PURE__ */ jsx26(Text24, { children: "\u{1F4B0} Save up to " }),
7502
- /* @__PURE__ */ jsxs24(Text24, { color: "green", bold: true, children: [
7503
- formatCurrency(Math.max(...results.map((r) => r.savings.annual))),
7504
- "/year"
7505
- ] }),
7506
- /* @__PURE__ */ jsx26(Text24, { children: " by switching to IntlPull" })
7507
- ] }),
7508
- /* @__PURE__ */ jsxs24(Box23, { marginTop: 1, children: [
7509
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Ready to switch? Run: " }),
7510
- /* @__PURE__ */ jsx26(Text24, { color: "cyan", children: "npx @intlpullhq/cli migrate from <provider>" })
7511
- ] }),
7512
- /* @__PURE__ */ jsxs24(Box23, { marginTop: 1, children: [
7513
- /* @__PURE__ */ jsx26(Text24, { dimColor: true, children: "Compare with your usage: " }),
7514
- /* @__PURE__ */ jsx26(Text24, { color: "cyan", children: "npx @intlpullhq/cli compare --keys 10000 --users 10" })
7515
- ] })
7516
- ] });
7517
- }
7518
- function runCompare(options) {
7519
- if (options.from) {
7520
- render10(/* @__PURE__ */ jsx26(CompareDisplay, { options }));
7521
- } else {
7522
- render10(/* @__PURE__ */ jsx26(CompareAllProviders, { options }));
7523
- }
7524
- }
7525
-
7526
7293
  // src/commands/check.tsx
7527
- import { useState as useState15, useEffect as useEffect12 } from "react";
7528
- import { render as render11, Box as Box25, Text as Text26 } from "ink";
7294
+ import { useState as useState14, useEffect as useEffect11 } from "react";
7295
+ import { render as render10, Box as Box24, Text as Text25 } from "ink";
7529
7296
  import { glob } from "glob";
7530
7297
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7531
7298
 
7532
7299
  // src/components/TaskList.tsx
7533
- import { Box as Box24, Text as Text25 } from "ink";
7534
- import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
7300
+ import { Box as Box23, Text as Text24 } from "ink";
7301
+ import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
7535
7302
  function getStatusIcon(status) {
7536
7303
  switch (status) {
7537
7304
  case "pending":
7538
- return /* @__PURE__ */ jsx27(Text25, { color: colors.textDim, children: icons.pending });
7305
+ return /* @__PURE__ */ jsx26(Text24, { color: colors.textDim, children: icons.pending });
7539
7306
  case "running":
7540
- return /* @__PURE__ */ jsx27(Spinner2, { type: "dots", color: colors.primary });
7307
+ return /* @__PURE__ */ jsx26(Spinner2, { type: "dots", color: colors.primary });
7541
7308
  case "success":
7542
- return /* @__PURE__ */ jsx27(Text25, { color: colors.success, children: icons.success });
7309
+ return /* @__PURE__ */ jsx26(Text24, { color: colors.success, children: icons.success });
7543
7310
  case "error":
7544
- return /* @__PURE__ */ jsx27(Text25, { color: colors.error, children: icons.error });
7311
+ return /* @__PURE__ */ jsx26(Text24, { color: colors.error, children: icons.error });
7545
7312
  case "warning":
7546
- return /* @__PURE__ */ jsx27(Text25, { color: colors.warning, children: icons.warning });
7313
+ return /* @__PURE__ */ jsx26(Text24, { color: colors.warning, children: icons.warning });
7547
7314
  case "skipped":
7548
- return /* @__PURE__ */ jsx27(Text25, { color: colors.textDim, children: icons.skipped });
7315
+ return /* @__PURE__ */ jsx26(Text24, { color: colors.textDim, children: icons.skipped });
7549
7316
  }
7550
7317
  }
7551
7318
  function getStatusColor(status) {
@@ -7565,20 +7332,20 @@ function getStatusColor(status) {
7565
7332
  }
7566
7333
  }
7567
7334
  function TaskList({ tasks, title }) {
7568
- return /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", marginY: 1, children: [
7569
- title && /* @__PURE__ */ jsx27(Box24, { marginBottom: 1, children: /* @__PURE__ */ jsx27(Text25, { bold: true, color: colors.text, children: title }) }),
7570
- tasks.map((task) => /* @__PURE__ */ jsxs25(Box24, { marginLeft: 1, children: [
7571
- /* @__PURE__ */ jsx27(Box24, { width: 3, children: getStatusIcon(task.status) }),
7572
- /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", children: [
7573
- /* @__PURE__ */ jsx27(Text25, { color: getStatusColor(task.status), children: task.label }),
7574
- task.output && task.status !== "pending" && /* @__PURE__ */ jsx27(Text25, { color: colors.textDim, dimColor: true, children: task.output })
7335
+ return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", marginY: 1, children: [
7336
+ title && /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, children: /* @__PURE__ */ jsx26(Text24, { bold: true, color: colors.text, children: title }) }),
7337
+ tasks.map((task) => /* @__PURE__ */ jsxs24(Box23, { marginLeft: 1, children: [
7338
+ /* @__PURE__ */ jsx26(Box23, { width: 3, children: getStatusIcon(task.status) }),
7339
+ /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", children: [
7340
+ /* @__PURE__ */ jsx26(Text24, { color: getStatusColor(task.status), children: task.label }),
7341
+ task.output && task.status !== "pending" && /* @__PURE__ */ jsx26(Text24, { color: colors.textDim, dimColor: true, children: task.output })
7575
7342
  ] })
7576
7343
  ] }, task.id))
7577
7344
  ] });
7578
7345
  }
7579
7346
 
7580
7347
  // src/commands/check.tsx
7581
- import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
7348
+ import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
7582
7349
  var LANG_CODE_REGEX = /^[a-z]{2}([-_][a-zA-Z]{2})?$/i;
7583
7350
  function CheckCommand({ options }) {
7584
7351
  const baseTasks = [
@@ -7593,17 +7360,17 @@ function CheckCommand({ options }) {
7593
7360
  if (options.output) {
7594
7361
  baseTasks.push({ id: "output", label: "Writing report file", status: "pending" });
7595
7362
  }
7596
- const [tasks, setTasks] = useState15(baseTasks);
7597
- const [result, setResult] = useState15(null);
7598
- const [fixResult, setFixResult] = useState15(null);
7599
- const [error, setError] = useState15(null);
7600
- const [done, setDone] = useState15(false);
7363
+ const [tasks, setTasks] = useState14(baseTasks);
7364
+ const [result, setResult] = useState14(null);
7365
+ const [fixResult, setFixResult] = useState14(null);
7366
+ const [error, setError] = useState14(null);
7367
+ const [done, setDone] = useState14(false);
7601
7368
  const updateTask = (id, update) => {
7602
7369
  setTasks(
7603
7370
  (prev) => prev.map((t) => t.id === id ? { ...t, ...update } : t)
7604
7371
  );
7605
7372
  };
7606
- useEffect12(() => {
7373
+ useEffect11(() => {
7607
7374
  async function run() {
7608
7375
  try {
7609
7376
  updateTask("config", { status: "running" });
@@ -7815,50 +7582,50 @@ ${parseErrors.join("\n")}`);
7815
7582
  }
7816
7583
  run();
7817
7584
  }, [options]);
7818
- return /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", children: [
7819
- /* @__PURE__ */ jsx28(Header, { compact: true }),
7820
- /* @__PURE__ */ jsx28(TaskList, { tasks, title: "Checking translations" }),
7821
- error && /* @__PURE__ */ jsx28(Alert, { type: "error", title: "Error", children: error }),
7822
- done && result && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7823
- result.missingKeys.length === 0 ? /* @__PURE__ */ jsxs26(Alert, { type: "success", title: "All translations complete", children: [
7585
+ return /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", children: [
7586
+ /* @__PURE__ */ jsx27(Header, { compact: true }),
7587
+ /* @__PURE__ */ jsx27(TaskList, { tasks, title: "Checking translations" }),
7588
+ error && /* @__PURE__ */ jsx27(Alert, { type: "error", title: "Error", children: error }),
7589
+ done && result && /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", marginTop: 1, children: [
7590
+ result.missingKeys.length === 0 ? /* @__PURE__ */ jsxs25(Alert, { type: "success", title: "All translations complete", children: [
7824
7591
  result.totalKeys,
7825
7592
  " keys are translated in all ",
7826
7593
  result.targetLanguages.length,
7827
7594
  " language(s)"
7828
- ] }) : /* @__PURE__ */ jsxs26(Alert, { type: "warning", title: "Missing translations found", children: [
7595
+ ] }) : /* @__PURE__ */ jsxs25(Alert, { type: "warning", title: "Missing translations found", children: [
7829
7596
  result.missingKeys.length,
7830
7597
  " key(s) missing across target languages"
7831
7598
  ] }),
7832
- /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7833
- /* @__PURE__ */ jsx28(Text26, { bold: true, color: colors.text, children: "Coverage:" }),
7834
- Object.entries(result.coveragePercentage).map(([lang, pct]) => /* @__PURE__ */ jsxs26(Box25, { marginLeft: 2, children: [
7835
- /* @__PURE__ */ jsx28(Text26, { color: pct === 100 ? colors.success : pct >= 80 ? colors.warning : colors.error, children: pct === 100 ? icons.success : icons.warning }),
7836
- /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
7599
+ /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", marginTop: 1, children: [
7600
+ /* @__PURE__ */ jsx27(Text25, { bold: true, color: colors.text, children: "Coverage:" }),
7601
+ Object.entries(result.coveragePercentage).map(([lang, pct]) => /* @__PURE__ */ jsxs25(Box24, { marginLeft: 2, children: [
7602
+ /* @__PURE__ */ jsx27(Text25, { color: pct === 100 ? colors.success : pct >= 80 ? colors.warning : colors.error, children: pct === 100 ? icons.success : icons.warning }),
7603
+ /* @__PURE__ */ jsxs25(Text25, { color: colors.textMuted, children: [
7837
7604
  " ",
7838
7605
  lang,
7839
7606
  ": ",
7840
- /* @__PURE__ */ jsxs26(Text26, { color: pct === 100 ? colors.success : colors.text, children: [
7607
+ /* @__PURE__ */ jsxs25(Text25, { color: pct === 100 ? colors.success : colors.text, children: [
7841
7608
  pct,
7842
7609
  "%"
7843
7610
  ] })
7844
7611
  ] })
7845
7612
  ] }, lang))
7846
7613
  ] }),
7847
- result.missingKeys.length > 0 && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7848
- /* @__PURE__ */ jsx28(Text26, { bold: true, color: colors.text, children: "Missing keys (first 10):" }),
7849
- result.missingKeys.map((mk, i) => /* @__PURE__ */ jsxs26(Box25, { marginLeft: 2, flexDirection: "column", children: [
7850
- /* @__PURE__ */ jsxs26(Text26, { color: colors.error, children: [
7614
+ result.missingKeys.length > 0 && /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", marginTop: 1, children: [
7615
+ /* @__PURE__ */ jsx27(Text25, { bold: true, color: colors.text, children: "Missing keys (first 10):" }),
7616
+ result.missingKeys.map((mk, i) => /* @__PURE__ */ jsxs25(Box24, { marginLeft: 2, flexDirection: "column", children: [
7617
+ /* @__PURE__ */ jsxs25(Text25, { color: colors.error, children: [
7851
7618
  "\u2022 ",
7852
7619
  mk.key
7853
7620
  ] }),
7854
- /* @__PURE__ */ jsx28(Box25, { marginLeft: 2, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
7621
+ /* @__PURE__ */ jsx27(Box24, { marginLeft: 2, children: /* @__PURE__ */ jsxs25(Text25, { color: colors.textMuted, children: [
7855
7622
  "Missing in: ",
7856
7623
  mk.missingIn.join(", ")
7857
7624
  ] }) })
7858
7625
  ] }, i))
7859
7626
  ] }),
7860
- fixResult && fixResult.keysAdded > 0 && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7861
- /* @__PURE__ */ jsxs26(Text26, { bold: true, color: colors.success, children: [
7627
+ fixResult && fixResult.keysAdded > 0 && /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", marginTop: 1, children: [
7628
+ /* @__PURE__ */ jsxs25(Text25, { bold: true, color: colors.success, children: [
7862
7629
  icons.success,
7863
7630
  " Fixed ",
7864
7631
  fixResult.keysAdded,
@@ -7866,22 +7633,22 @@ ${parseErrors.join("\n")}`);
7866
7633
  fixResult.filesModified,
7867
7634
  " file(s)"
7868
7635
  ] }),
7869
- /* @__PURE__ */ jsxs26(Box25, { marginTop: 1, children: [
7870
- /* @__PURE__ */ jsxs26(Text26, { color: colors.warning, children: [
7636
+ /* @__PURE__ */ jsxs25(Box24, { marginTop: 1, children: [
7637
+ /* @__PURE__ */ jsxs25(Text25, { color: colors.warning, children: [
7871
7638
  icons.warning,
7872
7639
  " "
7873
7640
  ] }),
7874
- /* @__PURE__ */ jsx28(Text26, { color: colors.textMuted, children: "Missing keys have been added with [LANG] prefix. Review and translate them." })
7641
+ /* @__PURE__ */ jsx27(Text25, { color: colors.textMuted, children: "Missing keys have been added with [LANG] prefix. Review and translate them." })
7875
7642
  ] })
7876
7643
  ] }),
7877
- !options.fix && result.missingKeys.length > 0 && /* @__PURE__ */ jsx28(Box25, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
7644
+ !options.fix && result.missingKeys.length > 0 && /* @__PURE__ */ jsx27(Box24, { marginTop: 1, children: /* @__PURE__ */ jsxs25(Text25, { color: colors.textMuted, children: [
7878
7645
  "Run ",
7879
- /* @__PURE__ */ jsx28(Text26, { color: colors.primary, children: "npx @intlpullhq/cli fix" }),
7646
+ /* @__PURE__ */ jsx27(Text25, { color: colors.primary, children: "npx @intlpullhq/cli fix" }),
7880
7647
  " to auto-generate missing translations"
7881
7648
  ] }) }),
7882
- options.output && /* @__PURE__ */ jsx28(Box25, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
7649
+ options.output && /* @__PURE__ */ jsx27(Box24, { marginTop: 1, children: /* @__PURE__ */ jsxs25(Text25, { color: colors.textMuted, children: [
7883
7650
  "Report saved to ",
7884
- /* @__PURE__ */ jsx28(Text26, { color: colors.primary, children: options.output })
7651
+ /* @__PURE__ */ jsx27(Text25, { color: colors.primary, children: options.output })
7885
7652
  ] }) })
7886
7653
  ] })
7887
7654
  ] });
@@ -7920,14 +7687,14 @@ function setNestedValue(obj, key, value) {
7920
7687
  current[parts[parts.length - 1]] = value;
7921
7688
  }
7922
7689
  function runCheck(options) {
7923
- render11(/* @__PURE__ */ jsx28(CheckCommand, { options }));
7690
+ render10(/* @__PURE__ */ jsx27(CheckCommand, { options }));
7924
7691
  }
7925
7692
 
7926
7693
  // src/commands/diff.tsx
7927
- import { useState as useState16, useEffect as useEffect13 } from "react";
7928
- import { render as render12, Box as Box26, Text as Text27 } from "ink";
7929
- import { readFileSync as readFileSync7, existsSync as existsSync6 } from "fs";
7930
- import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
7694
+ import { useState as useState15, useEffect as useEffect12 } from "react";
7695
+ import { render as render11, Box as Box25, Text as Text26 } from "ink";
7696
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
7697
+ import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
7931
7698
  async function fetchProjects5(apiUrl, apiKey) {
7932
7699
  const response = await fetch(`${apiUrl}/api/v1/projects`, {
7933
7700
  headers: { Accept: "application/json", "X-API-Key": apiKey }
@@ -7944,21 +7711,21 @@ async function fetchProjects5(apiUrl, apiKey) {
7944
7711
  }));
7945
7712
  }
7946
7713
  function DiffCommand({ options }) {
7947
- const [tasks, setTasks] = useState16([
7714
+ const [tasks, setTasks] = useState15([
7948
7715
  { id: "config", label: "Loading configuration", status: "pending" },
7949
7716
  { id: "local", label: "Reading local files", status: "pending" },
7950
7717
  { id: "remote", label: "Fetching from IntlPull", status: "pending" },
7951
7718
  { id: "compare", label: "Comparing changes", status: "pending" }
7952
7719
  ]);
7953
- const [result, setResult] = useState16(null);
7954
- const [error, setError] = useState16(null);
7955
- const [done, setDone] = useState16(false);
7720
+ const [result, setResult] = useState15(null);
7721
+ const [error, setError] = useState15(null);
7722
+ const [done, setDone] = useState15(false);
7956
7723
  const updateTask = (id, update) => {
7957
7724
  setTasks(
7958
7725
  (prev) => prev.map((t) => t.id === id ? { ...t, ...update } : t)
7959
7726
  );
7960
7727
  };
7961
- useEffect13(() => {
7728
+ useEffect12(() => {
7962
7729
  async function run() {
7963
7730
  try {
7964
7731
  updateTask("config", { status: "running" });
@@ -8006,7 +7773,7 @@ Or use a project-scoped API key for automatic selection.`
8006
7773
  ];
8007
7774
  let localFile = null;
8008
7775
  for (const path4 of possiblePaths) {
8009
- if (existsSync6(path4)) {
7776
+ if (existsSync7(path4)) {
8010
7777
  localFile = path4;
8011
7778
  break;
8012
7779
  }
@@ -8079,12 +7846,12 @@ Or use a project-scoped API key for automatic selection.`
8079
7846
  }
8080
7847
  run();
8081
7848
  }, [options.source, options.target]);
8082
- return /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
8083
- /* @__PURE__ */ jsx29(Header, { compact: true }),
8084
- /* @__PURE__ */ jsx29(TaskList, { tasks, title: "Computing diff" }),
8085
- error && /* @__PURE__ */ jsx29(Alert, { type: "error", title: "Error", children: error }),
8086
- done && result && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8087
- result.total === 0 ? /* @__PURE__ */ jsx29(Alert, { type: "success", title: "No changes", children: "Local files match IntlPull" }) : /* @__PURE__ */ jsxs27(Alert, { type: "info", title: "Changes detected", children: [
7849
+ return /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", children: [
7850
+ /* @__PURE__ */ jsx28(Header, { compact: true }),
7851
+ /* @__PURE__ */ jsx28(TaskList, { tasks, title: "Computing diff" }),
7852
+ error && /* @__PURE__ */ jsx28(Alert, { type: "error", title: "Error", children: error }),
7853
+ done && result && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7854
+ result.total === 0 ? /* @__PURE__ */ jsx28(Alert, { type: "success", title: "No changes", children: "Local files match IntlPull" }) : /* @__PURE__ */ jsxs26(Alert, { type: "info", title: "Changes detected", children: [
8088
7855
  result.added.length,
8089
7856
  " new locally, ",
8090
7857
  result.removed.length,
@@ -8092,79 +7859,79 @@ Or use a project-scoped API key for automatic selection.`
8092
7859
  result.changed.length,
8093
7860
  " modified"
8094
7861
  ] }),
8095
- result.added.length > 0 && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8096
- /* @__PURE__ */ jsxs27(Text27, { bold: true, color: colors.success, children: [
7862
+ result.added.length > 0 && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7863
+ /* @__PURE__ */ jsxs26(Text26, { bold: true, color: colors.success, children: [
8097
7864
  "+ New in local (",
8098
7865
  result.added.length,
8099
7866
  "):"
8100
7867
  ] }),
8101
- result.added.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs27(Box26, { marginLeft: 2, children: [
8102
- /* @__PURE__ */ jsx29(Text27, { color: colors.success, children: "+ " }),
8103
- /* @__PURE__ */ jsx29(Text27, { color: colors.text, children: entry.key }),
8104
- /* @__PURE__ */ jsxs27(Text27, { color: colors.textDim, children: [
7868
+ result.added.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs26(Box25, { marginLeft: 2, children: [
7869
+ /* @__PURE__ */ jsx28(Text26, { color: colors.success, children: "+ " }),
7870
+ /* @__PURE__ */ jsx28(Text26, { color: colors.text, children: entry.key }),
7871
+ /* @__PURE__ */ jsxs26(Text26, { color: colors.textDim, children: [
8105
7872
  ' = "',
8106
7873
  truncate(entry.newValue || "", 40),
8107
7874
  '"'
8108
7875
  ] })
8109
7876
  ] }, i)),
8110
- result.added.length > 5 && /* @__PURE__ */ jsx29(Box26, { marginLeft: 2, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
7877
+ result.added.length > 5 && /* @__PURE__ */ jsx28(Box25, { marginLeft: 2, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
8111
7878
  "... and ",
8112
7879
  result.added.length - 5,
8113
7880
  " more"
8114
7881
  ] }) })
8115
7882
  ] }),
8116
- result.removed.length > 0 && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8117
- /* @__PURE__ */ jsxs27(Text27, { bold: true, color: colors.error, children: [
7883
+ result.removed.length > 0 && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7884
+ /* @__PURE__ */ jsxs26(Text26, { bold: true, color: colors.error, children: [
8118
7885
  "- Missing locally (",
8119
7886
  result.removed.length,
8120
7887
  "):"
8121
7888
  ] }),
8122
- result.removed.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs27(Box26, { marginLeft: 2, children: [
8123
- /* @__PURE__ */ jsx29(Text27, { color: colors.error, children: "- " }),
8124
- /* @__PURE__ */ jsx29(Text27, { color: colors.text, children: entry.key })
7889
+ result.removed.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs26(Box25, { marginLeft: 2, children: [
7890
+ /* @__PURE__ */ jsx28(Text26, { color: colors.error, children: "- " }),
7891
+ /* @__PURE__ */ jsx28(Text26, { color: colors.text, children: entry.key })
8125
7892
  ] }, i)),
8126
- result.removed.length > 5 && /* @__PURE__ */ jsx29(Box26, { marginLeft: 2, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
7893
+ result.removed.length > 5 && /* @__PURE__ */ jsx28(Box25, { marginLeft: 2, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
8127
7894
  "... and ",
8128
7895
  result.removed.length - 5,
8129
7896
  " more"
8130
7897
  ] }) })
8131
7898
  ] }),
8132
- result.changed.length > 0 && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8133
- /* @__PURE__ */ jsxs27(Text27, { bold: true, color: colors.warning, children: [
7899
+ result.changed.length > 0 && /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", marginTop: 1, children: [
7900
+ /* @__PURE__ */ jsxs26(Text26, { bold: true, color: colors.warning, children: [
8134
7901
  "~ Modified (",
8135
7902
  result.changed.length,
8136
7903
  "):"
8137
7904
  ] }),
8138
- result.changed.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs27(Box26, { marginLeft: 2, flexDirection: "column", children: [
8139
- /* @__PURE__ */ jsxs27(Box26, { children: [
8140
- /* @__PURE__ */ jsx29(Text27, { color: colors.warning, children: "~ " }),
8141
- /* @__PURE__ */ jsx29(Text27, { color: colors.text, children: entry.key })
7905
+ result.changed.slice(0, 5).map((entry, i) => /* @__PURE__ */ jsxs26(Box25, { marginLeft: 2, flexDirection: "column", children: [
7906
+ /* @__PURE__ */ jsxs26(Box25, { children: [
7907
+ /* @__PURE__ */ jsx28(Text26, { color: colors.warning, children: "~ " }),
7908
+ /* @__PURE__ */ jsx28(Text26, { color: colors.text, children: entry.key })
8142
7909
  ] }),
8143
- /* @__PURE__ */ jsx29(Box26, { marginLeft: 4, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textDim, children: [
7910
+ /* @__PURE__ */ jsx28(Box25, { marginLeft: 4, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textDim, children: [
8144
7911
  'remote: "',
8145
7912
  truncate(entry.oldValue || "", 30),
8146
7913
  '"'
8147
7914
  ] }) }),
8148
- /* @__PURE__ */ jsx29(Box26, { marginLeft: 4, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textDim, children: [
7915
+ /* @__PURE__ */ jsx28(Box25, { marginLeft: 4, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textDim, children: [
8149
7916
  'local: "',
8150
7917
  truncate(entry.newValue || "", 30),
8151
7918
  '"'
8152
7919
  ] }) })
8153
7920
  ] }, i)),
8154
- result.changed.length > 5 && /* @__PURE__ */ jsx29(Box26, { marginLeft: 2, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
7921
+ result.changed.length > 5 && /* @__PURE__ */ jsx28(Box25, { marginLeft: 2, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
8155
7922
  "... and ",
8156
7923
  result.changed.length - 5,
8157
7924
  " more"
8158
7925
  ] }) })
8159
7926
  ] }),
8160
- result.added.length > 0 && /* @__PURE__ */ jsx29(Box26, { marginTop: 1, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
7927
+ result.added.length > 0 && /* @__PURE__ */ jsx28(Box25, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
8161
7928
  "Run ",
8162
- /* @__PURE__ */ jsx29(Text27, { color: colors.primary, children: "npx @intlpullhq/cli upload" }),
7929
+ /* @__PURE__ */ jsx28(Text26, { color: colors.primary, children: "npx @intlpullhq/cli upload" }),
8163
7930
  " to upload new keys to IntlPull"
8164
7931
  ] }) }),
8165
- result.removed.length > 0 && /* @__PURE__ */ jsx29(Box26, { marginTop: 1, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
7932
+ result.removed.length > 0 && /* @__PURE__ */ jsx28(Box25, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text26, { color: colors.textMuted, children: [
8166
7933
  "Run ",
8167
- /* @__PURE__ */ jsx29(Text27, { color: colors.primary, children: "npx @intlpullhq/cli download" }),
7934
+ /* @__PURE__ */ jsx28(Text26, { color: colors.primary, children: "npx @intlpullhq/cli download" }),
8168
7935
  " to download missing keys from IntlPull"
8169
7936
  ] }) })
8170
7937
  ] })
@@ -8184,30 +7951,30 @@ function truncate(str, length) {
8184
7951
  return str.length > length ? str.substring(0, length) + "..." : str;
8185
7952
  }
8186
7953
  function runDiff(options) {
8187
- render12(/* @__PURE__ */ jsx29(DiffCommand, { options }));
7954
+ render11(/* @__PURE__ */ jsx28(DiffCommand, { options }));
8188
7955
  }
8189
7956
 
8190
7957
  // src/commands/fix.tsx
8191
- import { useState as useState17, useEffect as useEffect14 } from "react";
8192
- import { render as render13, Box as Box27, Text as Text28 } from "ink";
7958
+ import { useState as useState16, useEffect as useEffect13 } from "react";
7959
+ import { render as render12, Box as Box26, Text as Text27 } from "ink";
8193
7960
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
8194
7961
  import { glob as glob2 } from "glob";
8195
- import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
7962
+ import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
8196
7963
  function FixCommand({ options }) {
8197
- const [tasks, setTasks] = useState17([
7964
+ const [tasks, setTasks] = useState16([
8198
7965
  { id: "config", label: "Loading configuration", status: "pending" },
8199
7966
  { id: "scan", label: "Scanning for missing keys", status: "pending" },
8200
7967
  { id: "fix", label: "Adding missing keys", status: "pending" }
8201
7968
  ]);
8202
- const [result, setResult] = useState17(null);
8203
- const [error, setError] = useState17(null);
8204
- const [done, setDone] = useState17(false);
7969
+ const [result, setResult] = useState16(null);
7970
+ const [error, setError] = useState16(null);
7971
+ const [done, setDone] = useState16(false);
8205
7972
  const updateTask = (id, update) => {
8206
7973
  setTasks(
8207
7974
  (prev) => prev.map((t) => t.id === id ? { ...t, ...update } : t)
8208
7975
  );
8209
7976
  };
8210
- useEffect14(() => {
7977
+ useEffect13(() => {
8211
7978
  async function run() {
8212
7979
  try {
8213
7980
  updateTask("config", { status: "running" });
@@ -8328,44 +8095,44 @@ ${parseErrors.join("\n")}`);
8328
8095
  }
8329
8096
  run();
8330
8097
  }, [options]);
8331
- return /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", children: [
8332
- /* @__PURE__ */ jsx30(Header, { compact: true }),
8333
- /* @__PURE__ */ jsx30(TaskList, { tasks, title: "Fixing missing translations" }),
8334
- error && /* @__PURE__ */ jsx30(Alert, { type: "error", title: "Error", children: error }),
8335
- done && result && /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", marginTop: 1, children: [
8336
- result.keysAdded === 0 ? /* @__PURE__ */ jsx30(Alert, { type: "success", title: "No fixes needed", children: "All translations are complete" }) : options.dryRun ? /* @__PURE__ */ jsxs28(Alert, { type: "warning", title: "Dry run complete", children: [
8098
+ return /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
8099
+ /* @__PURE__ */ jsx29(Header, { compact: true }),
8100
+ /* @__PURE__ */ jsx29(TaskList, { tasks, title: "Fixing missing translations" }),
8101
+ error && /* @__PURE__ */ jsx29(Alert, { type: "error", title: "Error", children: error }),
8102
+ done && result && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8103
+ result.keysAdded === 0 ? /* @__PURE__ */ jsx29(Alert, { type: "success", title: "No fixes needed", children: "All translations are complete" }) : options.dryRun ? /* @__PURE__ */ jsxs27(Alert, { type: "warning", title: "Dry run complete", children: [
8337
8104
  "Would add ",
8338
8105
  result.keysAdded,
8339
8106
  " missing key(s) to ",
8340
8107
  result.filesModified,
8341
8108
  " file(s)"
8342
- ] }) : /* @__PURE__ */ jsxs28(Alert, { type: "success", title: "Fix complete", children: [
8109
+ ] }) : /* @__PURE__ */ jsxs27(Alert, { type: "success", title: "Fix complete", children: [
8343
8110
  "Added ",
8344
8111
  result.keysAdded,
8345
8112
  " missing key(s) to ",
8346
8113
  result.filesModified,
8347
8114
  " file(s)"
8348
8115
  ] }),
8349
- result.keysAdded > 0 && /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", marginTop: 1, children: [
8350
- /* @__PURE__ */ jsx30(Text28, { bold: true, color: colors.text, children: "Languages fixed:" }),
8351
- result.languages.map((lang) => /* @__PURE__ */ jsxs28(Box27, { marginLeft: 2, children: [
8352
- /* @__PURE__ */ jsxs28(Text28, { color: colors.success, children: [
8116
+ result.keysAdded > 0 && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginTop: 1, children: [
8117
+ /* @__PURE__ */ jsx29(Text27, { bold: true, color: colors.text, children: "Languages fixed:" }),
8118
+ result.languages.map((lang) => /* @__PURE__ */ jsxs27(Box26, { marginLeft: 2, children: [
8119
+ /* @__PURE__ */ jsxs27(Text27, { color: colors.success, children: [
8353
8120
  icons.success,
8354
8121
  " "
8355
8122
  ] }),
8356
- /* @__PURE__ */ jsx30(Text28, { color: colors.text, children: lang })
8123
+ /* @__PURE__ */ jsx29(Text27, { color: colors.text, children: lang })
8357
8124
  ] }, lang))
8358
8125
  ] }),
8359
- result.keysAdded > 0 && !options.dryRun && /* @__PURE__ */ jsxs28(Box27, { marginTop: 1, children: [
8360
- /* @__PURE__ */ jsxs28(Text28, { color: colors.warning, children: [
8126
+ result.keysAdded > 0 && !options.dryRun && /* @__PURE__ */ jsxs27(Box26, { marginTop: 1, children: [
8127
+ /* @__PURE__ */ jsxs27(Text27, { color: colors.warning, children: [
8361
8128
  icons.warning,
8362
8129
  " "
8363
8130
  ] }),
8364
- /* @__PURE__ */ jsx30(Text28, { color: colors.textMuted, children: "Missing keys have been added with [LANG] prefix. Review and translate them." })
8131
+ /* @__PURE__ */ jsx29(Text27, { color: colors.textMuted, children: "Missing keys have been added with [LANG] prefix. Review and translate them." })
8365
8132
  ] }),
8366
- options.dryRun && result.keysAdded > 0 && /* @__PURE__ */ jsx30(Box27, { marginTop: 1, children: /* @__PURE__ */ jsxs28(Text28, { color: colors.textMuted, children: [
8133
+ options.dryRun && result.keysAdded > 0 && /* @__PURE__ */ jsx29(Box26, { marginTop: 1, children: /* @__PURE__ */ jsxs27(Text27, { color: colors.textMuted, children: [
8367
8134
  "Run without ",
8368
- /* @__PURE__ */ jsx30(Text28, { color: colors.primary, children: "--dry-run" }),
8135
+ /* @__PURE__ */ jsx29(Text27, { color: colors.primary, children: "--dry-run" }),
8369
8136
  " to apply fixes"
8370
8137
  ] }) })
8371
8138
  ] })
@@ -8395,16 +8162,16 @@ function setNestedValue2(obj, key, value) {
8395
8162
  current[parts[parts.length - 1]] = value;
8396
8163
  }
8397
8164
  function runFix(options) {
8398
- render13(/* @__PURE__ */ jsx30(FixCommand, { options }));
8165
+ render12(/* @__PURE__ */ jsx29(FixCommand, { options }));
8399
8166
  }
8400
8167
 
8401
8168
  // src/commands/listen.tsx
8402
- import { useState as useState18, useEffect as useEffect15, useCallback, useRef as useRef2 } from "react";
8403
- import { render as render14, Box as Box28, Text as Text29, useApp as useApp6, useInput as useInput7 } from "ink";
8404
- import Spinner13 from "ink-spinner";
8405
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
8406
- import { join as join7 } from "path";
8407
- import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
8169
+ import { useState as useState17, useEffect as useEffect14, useCallback, useRef as useRef2 } from "react";
8170
+ import { render as render13, Box as Box27, Text as Text28, useApp as useApp6, useInput as useInput7 } from "ink";
8171
+ import Spinner12 from "ink-spinner";
8172
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync9 } from "fs";
8173
+ import { join as join8 } from "path";
8174
+ import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
8408
8175
  async function fetchProjects6(apiUrl, apiKey) {
8409
8176
  const response = await fetch(`${apiUrl}/api/v1/projects`, {
8410
8177
  headers: { Accept: "application/json", "X-API-Key": apiKey }
@@ -8541,9 +8308,9 @@ function writeTranslationFiles(bundle, outputDir, format, languages) {
8541
8308
  const targetLanguages = languages || Object.keys(bundle);
8542
8309
  for (const locale of targetLanguages) {
8543
8310
  if (!bundle[locale]) continue;
8544
- const localeDir = join7(outputDir, locale);
8545
- if (!existsSync8(localeDir)) {
8546
- mkdirSync3(localeDir, { recursive: true });
8311
+ const localeDir = join8(outputDir, locale);
8312
+ if (!existsSync9(localeDir)) {
8313
+ mkdirSync4(localeDir, { recursive: true });
8547
8314
  }
8548
8315
  let content;
8549
8316
  let filename;
@@ -8563,7 +8330,7 @@ function writeTranslationFiles(bundle, outputDir, format, languages) {
8563
8330
  filename = "translations.json";
8564
8331
  break;
8565
8332
  }
8566
- const filePath = join7(localeDir, filename);
8333
+ const filePath = join8(localeDir, filename);
8567
8334
  writeFileSync6(filePath, content);
8568
8335
  writtenFiles.push(filePath);
8569
8336
  }
@@ -8586,7 +8353,7 @@ function formatRelativeTime(date) {
8586
8353
  }
8587
8354
  function ListenComponent({ options }) {
8588
8355
  const { exit } = useApp6();
8589
- const [state, setState] = useState18({
8356
+ const [state, setState] = useState17({
8590
8357
  status: "connecting",
8591
8358
  message: "Connecting to IntlPull...",
8592
8359
  lastSync: null,
@@ -8710,7 +8477,7 @@ function ListenComponent({ options }) {
8710
8477
  }));
8711
8478
  }
8712
8479
  }, [options, state.version, state.syncCount]);
8713
- useEffect15(() => {
8480
+ useEffect14(() => {
8714
8481
  sync();
8715
8482
  if (options.once) {
8716
8483
  return;
@@ -8722,7 +8489,7 @@ function ListenComponent({ options }) {
8722
8489
  }, intervalMs);
8723
8490
  return () => clearInterval(interval);
8724
8491
  }, [sync, intervalMs, options.once]);
8725
- useEffect15(() => {
8492
+ useEffect14(() => {
8726
8493
  if (!options.timeout || options.once) return;
8727
8494
  const timeoutMs = options.timeout * 1e3;
8728
8495
  const timer = setTimeout(() => {
@@ -8735,7 +8502,7 @@ function ListenComponent({ options }) {
8735
8502
  }, timeoutMs);
8736
8503
  return () => clearTimeout(timer);
8737
8504
  }, [options.timeout, options.once, exit]);
8738
- useEffect15(() => {
8505
+ useEffect14(() => {
8739
8506
  if (options.once && state.status === "watching") {
8740
8507
  setTimeout(() => exit(), 100);
8741
8508
  }
@@ -8754,57 +8521,57 @@ function ListenComponent({ options }) {
8754
8521
  error: "\u2717",
8755
8522
  stopped: "\u25FB"
8756
8523
  }[state.status];
8757
- return /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", paddingX: 1, children: [
8758
- /* @__PURE__ */ jsxs29(Box28, { marginBottom: 1, children: [
8759
- /* @__PURE__ */ jsx31(Text29, { bold: true, color: "cyan", children: "IntlPull" }),
8760
- /* @__PURE__ */ jsx31(Text29, { children: " \u2022 Live Sync" }),
8761
- isInteractive && /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: " (press q to quit)" })
8524
+ return /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", paddingX: 1, children: [
8525
+ /* @__PURE__ */ jsxs28(Box27, { marginBottom: 1, children: [
8526
+ /* @__PURE__ */ jsx30(Text28, { bold: true, color: "cyan", children: "IntlPull" }),
8527
+ /* @__PURE__ */ jsx30(Text28, { children: " \u2022 Live Sync" }),
8528
+ isInteractive && /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: " (press q to quit)" })
8762
8529
  ] }),
8763
- /* @__PURE__ */ jsxs29(Box28, { children: [
8764
- state.status === "syncing" ? /* @__PURE__ */ jsx31(Text29, { color: "cyan", children: /* @__PURE__ */ jsx31(Spinner13, { type: "dots" }) }) : /* @__PURE__ */ jsx31(Text29, { color: statusColor, children: statusIcon }),
8765
- /* @__PURE__ */ jsx31(Text29, { children: " " }),
8766
- /* @__PURE__ */ jsx31(Text29, { color: statusColor, children: state.message })
8530
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8531
+ state.status === "syncing" ? /* @__PURE__ */ jsx30(Text28, { color: "cyan", children: /* @__PURE__ */ jsx30(Spinner12, { type: "dots" }) }) : /* @__PURE__ */ jsx30(Text28, { color: statusColor, children: statusIcon }),
8532
+ /* @__PURE__ */ jsx30(Text28, { children: " " }),
8533
+ /* @__PURE__ */ jsx30(Text28, { color: statusColor, children: state.message })
8767
8534
  ] }),
8768
- state.error && /* @__PURE__ */ jsxs29(Box28, { marginTop: 1, flexDirection: "column", children: [
8769
- /* @__PURE__ */ jsx31(Text29, { color: "red", children: state.error }),
8770
- /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
8535
+ state.error && /* @__PURE__ */ jsxs28(Box27, { marginTop: 1, flexDirection: "column", children: [
8536
+ /* @__PURE__ */ jsx30(Text28, { color: "red", children: state.error }),
8537
+ /* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
8771
8538
  "Retrying in ",
8772
8539
  intervalMs / 1e3,
8773
8540
  "s..."
8774
8541
  ] })
8775
8542
  ] }),
8776
- state.lastSync && !options.quiet && /* @__PURE__ */ jsxs29(Box28, { marginTop: 1, flexDirection: "column", children: [
8777
- /* @__PURE__ */ jsxs29(Box28, { children: [
8778
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Output: " }),
8779
- /* @__PURE__ */ jsx31(Text29, { children: state.outputDir })
8543
+ state.lastSync && !options.quiet && /* @__PURE__ */ jsxs28(Box27, { marginTop: 1, flexDirection: "column", children: [
8544
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8545
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Output: " }),
8546
+ /* @__PURE__ */ jsx30(Text28, { children: state.outputDir })
8780
8547
  ] }),
8781
- /* @__PURE__ */ jsxs29(Box28, { children: [
8782
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Version: " }),
8783
- /* @__PURE__ */ jsx31(Text29, { children: state.version })
8548
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8549
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Version: " }),
8550
+ /* @__PURE__ */ jsx30(Text28, { children: state.version })
8784
8551
  ] }),
8785
- /* @__PURE__ */ jsxs29(Box28, { children: [
8786
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Languages: " }),
8787
- /* @__PURE__ */ jsx31(Text29, { children: state.languages.join(", ") })
8552
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8553
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Languages: " }),
8554
+ /* @__PURE__ */ jsx30(Text28, { children: state.languages.join(", ") })
8788
8555
  ] }),
8789
- /* @__PURE__ */ jsxs29(Box28, { children: [
8790
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Keys: " }),
8791
- /* @__PURE__ */ jsx31(Text29, { children: state.keyCount })
8556
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8557
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Keys: " }),
8558
+ /* @__PURE__ */ jsx30(Text28, { children: state.keyCount })
8792
8559
  ] }),
8793
- /* @__PURE__ */ jsxs29(Box28, { children: [
8794
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Last sync: " }),
8795
- /* @__PURE__ */ jsxs29(Text29, { children: [
8560
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8561
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Last sync: " }),
8562
+ /* @__PURE__ */ jsxs28(Text28, { children: [
8796
8563
  formatTime(state.lastSync),
8797
8564
  " (",
8798
8565
  formatRelativeTime(state.lastSync),
8799
8566
  ")"
8800
8567
  ] })
8801
8568
  ] }),
8802
- /* @__PURE__ */ jsxs29(Box28, { children: [
8803
- /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Syncs: " }),
8804
- /* @__PURE__ */ jsx31(Text29, { children: state.syncCount })
8569
+ /* @__PURE__ */ jsxs28(Box27, { children: [
8570
+ /* @__PURE__ */ jsx30(Text28, { dimColor: true, children: "Syncs: " }),
8571
+ /* @__PURE__ */ jsx30(Text28, { children: state.syncCount })
8805
8572
  ] })
8806
8573
  ] }),
8807
- state.status === "watching" && !options.once && !options.quiet && /* @__PURE__ */ jsx31(Box28, { marginTop: 1, children: /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
8574
+ state.status === "watching" && !options.once && !options.quiet && /* @__PURE__ */ jsx30(Box27, { marginTop: 1, children: /* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
8808
8575
  "Polling every ",
8809
8576
  intervalMs / 1e3,
8810
8577
  "s for changes..."
@@ -8927,14 +8694,14 @@ function runListen(options) {
8927
8694
  runOnceSync(options);
8928
8695
  return;
8929
8696
  }
8930
- render14(/* @__PURE__ */ jsx31(ListenComponent, { options }));
8697
+ render13(/* @__PURE__ */ jsx30(ListenComponent, { options }));
8931
8698
  }
8932
8699
 
8933
8700
  // src/commands/publish.tsx
8934
- import { useState as useState19, useEffect as useEffect16 } from "react";
8935
- import { render as render15, Box as Box29, Text as Text30 } from "ink";
8936
- import Spinner14 from "ink-spinner";
8937
- import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
8701
+ import { useState as useState18, useEffect as useEffect15 } from "react";
8702
+ import { render as render14, Box as Box28, Text as Text29 } from "ink";
8703
+ import Spinner13 from "ink-spinner";
8704
+ import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
8938
8705
  async function fetchProjects7(apiUrl, apiKey) {
8939
8706
  const response = await fetch(`${apiUrl}/api/v1/projects`, {
8940
8707
  headers: { Accept: "application/json", "X-API-Key": apiKey }
@@ -9104,11 +8871,11 @@ function generateVersion() {
9104
8871
  return `${now.getFullYear()}.${now.getMonth() + 1}.${now.getDate()}-${now.getHours()}${now.getMinutes()}`;
9105
8872
  }
9106
8873
  function PublishComponent({ options }) {
9107
- const [state, setState] = useState19({
8874
+ const [state, setState] = useState18({
9108
8875
  status: "detecting",
9109
8876
  message: "Detecting project..."
9110
8877
  });
9111
- useEffect16(() => {
8878
+ useEffect15(() => {
9112
8879
  async function run() {
9113
8880
  try {
9114
8881
  const resolved = getResolvedApiKey();
@@ -9192,96 +8959,96 @@ function PublishComponent({ options }) {
9192
8959
  }
9193
8960
  return null;
9194
8961
  }
9195
- return /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", paddingX: 1, children: [
9196
- /* @__PURE__ */ jsxs30(Box29, { marginBottom: 1, children: [
9197
- /* @__PURE__ */ jsx32(Text30, { bold: true, color: "cyan", children: "IntlPull" }),
9198
- /* @__PURE__ */ jsx32(Text30, { children: " Publish OTA Release" }),
9199
- options.dryRun && /* @__PURE__ */ jsx32(Text30, { color: "yellow", children: " (dry run)" })
8962
+ return /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", paddingX: 1, children: [
8963
+ /* @__PURE__ */ jsxs29(Box28, { marginBottom: 1, children: [
8964
+ /* @__PURE__ */ jsx31(Text29, { bold: true, color: "cyan", children: "IntlPull" }),
8965
+ /* @__PURE__ */ jsx31(Text29, { children: " Publish OTA Release" }),
8966
+ options.dryRun && /* @__PURE__ */ jsx31(Text29, { color: "yellow", children: " (dry run)" })
9200
8967
  ] }),
9201
- (state.status === "detecting" || state.status === "publishing") && /* @__PURE__ */ jsxs30(Box29, { children: [
9202
- /* @__PURE__ */ jsx32(Text30, { color: "cyan", children: /* @__PURE__ */ jsx32(Spinner14, { type: "dots" }) }),
9203
- /* @__PURE__ */ jsxs30(Text30, { children: [
8968
+ (state.status === "detecting" || state.status === "publishing") && /* @__PURE__ */ jsxs29(Box28, { children: [
8969
+ /* @__PURE__ */ jsx31(Text29, { color: "cyan", children: /* @__PURE__ */ jsx31(Spinner13, { type: "dots" }) }),
8970
+ /* @__PURE__ */ jsxs29(Text29, { children: [
9204
8971
  " ",
9205
8972
  state.message
9206
8973
  ] })
9207
8974
  ] }),
9208
- state.status === "success" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9209
- /* @__PURE__ */ jsxs30(Text30, { color: "green", children: [
8975
+ state.status === "success" && /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", children: [
8976
+ /* @__PURE__ */ jsxs29(Text29, { color: "green", children: [
9210
8977
  "\u2713 ",
9211
8978
  state.message
9212
8979
  ] }),
9213
- state.projectName && /* @__PURE__ */ jsx32(Box29, { marginTop: 1, children: /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
8980
+ state.projectName && /* @__PURE__ */ jsx31(Box28, { marginTop: 1, children: /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9214
8981
  "Project: ",
9215
- /* @__PURE__ */ jsx32(Text30, { color: "white", children: state.projectName })
8982
+ /* @__PURE__ */ jsx31(Text29, { color: "white", children: state.projectName })
9216
8983
  ] }) }),
9217
- state.branch && /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
8984
+ state.branch && /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9218
8985
  "Branch: ",
9219
- /* @__PURE__ */ jsx32(Text30, { color: "white", children: state.branch })
8986
+ /* @__PURE__ */ jsx31(Text29, { color: "white", children: state.branch })
9220
8987
  ] }),
9221
- state.release && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: 1, children: [
9222
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
8988
+ state.release && /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", marginTop: 1, children: [
8989
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9223
8990
  "Version: ",
9224
- /* @__PURE__ */ jsx32(Text30, { color: "green", bold: true, children: state.release.version })
8991
+ /* @__PURE__ */ jsx31(Text29, { color: "green", bold: true, children: state.release.version })
9225
8992
  ] }),
9226
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
8993
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9227
8994
  "Languages: ",
9228
8995
  state.release.languages.join(", ")
9229
8996
  ] }),
9230
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
8997
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9231
8998
  "Keys: ",
9232
8999
  state.release.keyCount
9233
9000
  ] }),
9234
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9001
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9235
9002
  "Bundle size: ",
9236
9003
  formatBytes(state.release.bundleSize)
9237
9004
  ] }),
9238
- /* @__PURE__ */ jsxs30(Box29, { marginTop: 1, flexDirection: "column", children: [
9239
- /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "SDK Manifest URL:" }),
9240
- /* @__PURE__ */ jsxs30(Text30, { color: "cyan", children: [
9005
+ /* @__PURE__ */ jsxs29(Box28, { marginTop: 1, flexDirection: "column", children: [
9006
+ /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "SDK Manifest URL:" }),
9007
+ /* @__PURE__ */ jsxs29(Text29, { color: "cyan", children: [
9241
9008
  " ",
9242
9009
  state.release.bundleUrl.replace(/\/[^/]+\.json$/, "/manifest")
9243
9010
  ] })
9244
9011
  ] })
9245
9012
  ] }),
9246
- !state.release && state.summary && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: 1, children: [
9247
- /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "Would publish:" }),
9248
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9013
+ !state.release && state.summary && /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", marginTop: 1, children: [
9014
+ /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Would publish:" }),
9015
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9249
9016
  " Languages: ",
9250
9017
  state.summary.languages.join(", ")
9251
9018
  ] }),
9252
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9019
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9253
9020
  " Keys: ",
9254
9021
  state.summary.keyCount
9255
9022
  ] }),
9256
- /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9023
+ /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
9257
9024
  " Estimated size: ",
9258
9025
  formatBytes(state.summary.estimatedSize)
9259
9026
  ] })
9260
9027
  ] })
9261
9028
  ] }),
9262
- state.status === "error" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9263
- /* @__PURE__ */ jsxs30(Text30, { color: "red", children: [
9029
+ state.status === "error" && /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", children: [
9030
+ /* @__PURE__ */ jsxs29(Text29, { color: "red", children: [
9264
9031
  "\u2717 ",
9265
9032
  state.message
9266
9033
  ] }),
9267
- /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: 1, children: [
9268
- /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "Tips:" }),
9269
- /* @__PURE__ */ jsx32(Text30, { color: "gray", children: " \u2022 Run `npx @intlpullhq/cli upload` to upload translations first" }),
9270
- /* @__PURE__ */ jsx32(Text30, { color: "gray", children: " \u2022 Use `npx @intlpullhq/cli publish 1.0.0` to specify a version" }),
9271
- /* @__PURE__ */ jsx32(Text30, { color: "gray", children: " \u2022 Use `npx @intlpullhq/cli publish --dry-run` to preview" })
9034
+ /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", marginTop: 1, children: [
9035
+ /* @__PURE__ */ jsx31(Text29, { dimColor: true, children: "Tips:" }),
9036
+ /* @__PURE__ */ jsx31(Text29, { color: "gray", children: " \u2022 Run `npx @intlpullhq/cli upload` to upload translations first" }),
9037
+ /* @__PURE__ */ jsx31(Text29, { color: "gray", children: " \u2022 Use `npx @intlpullhq/cli publish 1.0.0` to specify a version" }),
9038
+ /* @__PURE__ */ jsx31(Text29, { color: "gray", children: " \u2022 Use `npx @intlpullhq/cli publish --dry-run` to preview" })
9272
9039
  ] })
9273
9040
  ] })
9274
9041
  ] });
9275
9042
  }
9276
9043
  function runPublish(options) {
9277
- render15(/* @__PURE__ */ jsx32(PublishComponent, { options }));
9044
+ render14(/* @__PURE__ */ jsx31(PublishComponent, { options }));
9278
9045
  }
9279
9046
 
9280
9047
  // src/commands/releases.tsx
9281
- import { useState as useState20, useEffect as useEffect17 } from "react";
9282
- import { render as render16, Box as Box30, Text as Text31 } from "ink";
9283
- import Spinner15 from "ink-spinner";
9284
- import { jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
9048
+ import { useState as useState19, useEffect as useEffect16 } from "react";
9049
+ import { render as render15, Box as Box29, Text as Text30 } from "ink";
9050
+ import Spinner14 from "ink-spinner";
9051
+ import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
9285
9052
  async function fetchProjects8(apiUrl, apiKey) {
9286
9053
  const response = await fetch(`${apiUrl}/api/v1/projects`, {
9287
9054
  headers: { Accept: "application/json", "X-API-Key": apiKey }
@@ -9355,11 +9122,11 @@ function formatDate(dateStr) {
9355
9122
  });
9356
9123
  }
9357
9124
  function ReleasesComponent({ options }) {
9358
- const [state, setState] = useState20({
9125
+ const [state, setState] = useState19({
9359
9126
  status: "loading",
9360
9127
  message: "Loading releases..."
9361
9128
  });
9362
- useEffect17(() => {
9129
+ useEffect16(() => {
9363
9130
  async function run() {
9364
9131
  try {
9365
9132
  const resolved = getResolvedApiKey();
@@ -9424,41 +9191,41 @@ function ReleasesComponent({ options }) {
9424
9191
  }
9425
9192
  return null;
9426
9193
  }
9427
- return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", paddingX: 1, children: [
9428
- /* @__PURE__ */ jsxs31(Box30, { marginBottom: 1, children: [
9429
- /* @__PURE__ */ jsx33(Text31, { bold: true, color: "cyan", children: "IntlPull" }),
9430
- /* @__PURE__ */ jsx33(Text31, { children: " OTA Releases" })
9194
+ return /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", paddingX: 1, children: [
9195
+ /* @__PURE__ */ jsxs30(Box29, { marginBottom: 1, children: [
9196
+ /* @__PURE__ */ jsx32(Text30, { bold: true, color: "cyan", children: "IntlPull" }),
9197
+ /* @__PURE__ */ jsx32(Text30, { children: " OTA Releases" })
9431
9198
  ] }),
9432
- state.status === "loading" && /* @__PURE__ */ jsxs31(Box30, { children: [
9433
- /* @__PURE__ */ jsx33(Text31, { color: "cyan", children: /* @__PURE__ */ jsx33(Spinner15, { type: "dots" }) }),
9434
- /* @__PURE__ */ jsxs31(Text31, { children: [
9199
+ state.status === "loading" && /* @__PURE__ */ jsxs30(Box29, { children: [
9200
+ /* @__PURE__ */ jsx32(Text30, { color: "cyan", children: /* @__PURE__ */ jsx32(Spinner14, { type: "dots" }) }),
9201
+ /* @__PURE__ */ jsxs30(Text30, { children: [
9435
9202
  " ",
9436
9203
  state.message
9437
9204
  ] })
9438
9205
  ] }),
9439
- state.status === "success" && state.deleted && /* @__PURE__ */ jsxs31(Text31, { color: "green", children: [
9206
+ state.status === "success" && state.deleted && /* @__PURE__ */ jsxs30(Text30, { color: "green", children: [
9440
9207
  "\u2713 ",
9441
9208
  state.message
9442
9209
  ] }),
9443
- state.status === "success" && state.releases && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9444
- state.projectName && /* @__PURE__ */ jsx33(Box30, { marginBottom: 1, children: /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9210
+ state.status === "success" && state.releases && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9211
+ state.projectName && /* @__PURE__ */ jsx32(Box29, { marginBottom: 1, children: /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9445
9212
  "Project: ",
9446
- /* @__PURE__ */ jsx33(Text31, { color: "white", children: state.projectName })
9213
+ /* @__PURE__ */ jsx32(Text30, { color: "white", children: state.projectName })
9447
9214
  ] }) }),
9448
- state.releases.length === 0 ? /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9449
- /* @__PURE__ */ jsx33(Text31, { color: "yellow", children: "No releases found" }),
9450
- /* @__PURE__ */ jsx33(Box30, { marginTop: 1, children: /* @__PURE__ */ jsx33(Text31, { dimColor: true, children: "Run `npx @intlpullhq/cli publish [version]` to create your first OTA release." }) })
9451
- ] }) : /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9452
- state.releases.map((release, i) => /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginBottom: i < state.releases.length - 1 ? 1 : 0, children: [
9453
- /* @__PURE__ */ jsxs31(Box30, { children: [
9454
- /* @__PURE__ */ jsx33(Text31, { color: "green", bold: true, children: release.version }),
9455
- /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9215
+ state.releases.length === 0 ? /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9216
+ /* @__PURE__ */ jsx32(Text30, { color: "yellow", children: "No releases found" }),
9217
+ /* @__PURE__ */ jsx32(Box29, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "Run `npx @intlpullhq/cli publish [version]` to create your first OTA release." }) })
9218
+ ] }) : /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9219
+ state.releases.map((release, i) => /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginBottom: i < state.releases.length - 1 ? 1 : 0, children: [
9220
+ /* @__PURE__ */ jsxs30(Box29, { children: [
9221
+ /* @__PURE__ */ jsx32(Text30, { color: "green", bold: true, children: release.version }),
9222
+ /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9456
9223
  " \u2022 ",
9457
9224
  formatDate(release.publishedAt)
9458
9225
  ] }),
9459
- i === 0 && /* @__PURE__ */ jsx33(Text31, { color: "cyan", children: " (latest)" })
9226
+ i === 0 && /* @__PURE__ */ jsx32(Text30, { color: "cyan", children: " (latest)" })
9460
9227
  ] }),
9461
- /* @__PURE__ */ jsx33(Box30, { paddingLeft: 2, children: /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9228
+ /* @__PURE__ */ jsx32(Box29, { paddingLeft: 2, children: /* @__PURE__ */ jsxs30(Text30, { dimColor: true, children: [
9462
9229
  release.keyCount,
9463
9230
  " keys \u2022 ",
9464
9231
  release.languages.length,
@@ -9466,44 +9233,44 @@ function ReleasesComponent({ options }) {
9466
9233
  formatBytes2(release.bundleSize),
9467
9234
  release.downloadCount > 0 && ` \u2022 ${release.downloadCount} downloads`
9468
9235
  ] }) }),
9469
- /* @__PURE__ */ jsx33(Box30, { paddingLeft: 2, children: /* @__PURE__ */ jsxs31(Text31, { color: "gray", children: [
9236
+ /* @__PURE__ */ jsx32(Box29, { paddingLeft: 2, children: /* @__PURE__ */ jsxs30(Text30, { color: "gray", children: [
9470
9237
  "ID: ",
9471
9238
  release.id
9472
9239
  ] }) })
9473
9240
  ] }, release.id)),
9474
- /* @__PURE__ */ jsx33(Box30, { marginTop: 1, children: /* @__PURE__ */ jsx33(Text31, { dimColor: true, children: "Use `npx @intlpullhq/cli releases delete <id>` to delete a release." }) })
9241
+ /* @__PURE__ */ jsx32(Box29, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "Use `npx @intlpullhq/cli releases delete <id>` to delete a release." }) })
9475
9242
  ] })
9476
9243
  ] }),
9477
- state.status === "error" && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9478
- /* @__PURE__ */ jsxs31(Text31, { color: "red", children: [
9244
+ state.status === "error" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
9245
+ /* @__PURE__ */ jsxs30(Text30, { color: "red", children: [
9479
9246
  "\u2717 ",
9480
9247
  state.message
9481
9248
  ] }),
9482
- /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: 1, children: [
9483
- /* @__PURE__ */ jsx33(Text31, { dimColor: true, children: "Tips:" }),
9484
- /* @__PURE__ */ jsx33(Text31, { color: "gray", children: " \u2022 Run `npx @intlpullhq/cli publish` to create a release first" }),
9485
- /* @__PURE__ */ jsx33(Text31, { color: "gray", children: " \u2022 OTA requires Professional or Enterprise plan" })
9249
+ /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: 1, children: [
9250
+ /* @__PURE__ */ jsx32(Text30, { dimColor: true, children: "Tips:" }),
9251
+ /* @__PURE__ */ jsx32(Text30, { color: "gray", children: " \u2022 Run `npx @intlpullhq/cli publish` to create a release first" }),
9252
+ /* @__PURE__ */ jsx32(Text30, { color: "gray", children: " \u2022 OTA requires Professional or Enterprise plan" })
9486
9253
  ] })
9487
9254
  ] })
9488
9255
  ] });
9489
9256
  }
9490
9257
  function runReleases(options) {
9491
- render16(/* @__PURE__ */ jsx33(ReleasesComponent, { options }));
9258
+ render15(/* @__PURE__ */ jsx32(ReleasesComponent, { options }));
9492
9259
  }
9493
9260
 
9494
9261
  // src/commands/workflow.tsx
9495
- import { useState as useState21, useEffect as useEffect18 } from "react";
9496
- import { render as render17, Box as Box31, Text as Text32 } from "ink";
9497
- import { Fragment as Fragment5, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
9262
+ import { useState as useState20, useEffect as useEffect17 } from "react";
9263
+ import { render as render16, Box as Box30, Text as Text31 } from "ink";
9264
+ import { Fragment as Fragment5, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
9498
9265
  function WorkflowStatusCommand({ projectId }) {
9499
- const [loading, setLoading] = useState21(true);
9500
- const [error, setError] = useState21(null);
9501
- const [projectName, setProjectName] = useState21("");
9502
- const [workflowsEnabled, setWorkflowsEnabled] = useState21(false);
9503
- const [workflows, setWorkflows] = useState21([]);
9504
- const [pending, setPending] = useState21([]);
9505
- const [locked, setLocked] = useState21([]);
9506
- useEffect18(() => {
9266
+ const [loading, setLoading] = useState20(true);
9267
+ const [error, setError] = useState20(null);
9268
+ const [projectName, setProjectName] = useState20("");
9269
+ const [workflowsEnabled, setWorkflowsEnabled] = useState20(false);
9270
+ const [workflows, setWorkflows] = useState20([]);
9271
+ const [pending, setPending] = useState20([]);
9272
+ const [locked, setLocked] = useState20([]);
9273
+ useEffect17(() => {
9507
9274
  async function fetchData() {
9508
9275
  const resolved = getResolvedApiKey();
9509
9276
  if (!resolved?.key) {
@@ -9543,36 +9310,36 @@ function WorkflowStatusCommand({ projectId }) {
9543
9310
  }
9544
9311
  fetchData();
9545
9312
  }, [projectId]);
9546
- return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9547
- /* @__PURE__ */ jsx34(Header, { compact: true }),
9548
- loading && /* @__PURE__ */ jsx34(Box31, { marginY: 1, children: /* @__PURE__ */ jsx34(Spinner2, { label: "Fetching workflow status..." }) }),
9549
- error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Error", children: error }),
9550
- !loading && !error && !workflowsEnabled && /* @__PURE__ */ jsxs32(Alert, { type: "warning", title: "Workflows Not Enabled", children: [
9313
+ return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9314
+ /* @__PURE__ */ jsx33(Header, { compact: true }),
9315
+ loading && /* @__PURE__ */ jsx33(Box30, { marginY: 1, children: /* @__PURE__ */ jsx33(Spinner2, { label: "Fetching workflow status..." }) }),
9316
+ error && /* @__PURE__ */ jsx33(Alert, { type: "error", title: "Error", children: error }),
9317
+ !loading && !error && !workflowsEnabled && /* @__PURE__ */ jsxs31(Alert, { type: "warning", title: "Workflows Not Enabled", children: [
9551
9318
  'Workflows are not enabled for project "',
9552
9319
  projectName,
9553
9320
  '".',
9554
9321
  "\n",
9555
9322
  "Enable them in the project settings at app.intlpull.com"
9556
9323
  ] }),
9557
- !loading && !error && workflowsEnabled && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9558
- /* @__PURE__ */ jsx34(
9559
- Box31,
9324
+ !loading && !error && workflowsEnabled && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9325
+ /* @__PURE__ */ jsx33(
9326
+ Box30,
9560
9327
  {
9561
9328
  borderStyle: "round",
9562
9329
  borderColor: colors.primary,
9563
9330
  paddingX: 2,
9564
9331
  paddingY: 1,
9565
9332
  marginY: 1,
9566
- children: /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9567
- /* @__PURE__ */ jsxs32(Box31, { children: [
9568
- /* @__PURE__ */ jsx34(Text32, { bold: true, color: colors.text, children: projectName }),
9569
- /* @__PURE__ */ jsxs32(Text32, { color: colors.success, children: [
9333
+ children: /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9334
+ /* @__PURE__ */ jsxs31(Box30, { children: [
9335
+ /* @__PURE__ */ jsx33(Text31, { bold: true, color: colors.text, children: projectName }),
9336
+ /* @__PURE__ */ jsxs31(Text31, { color: colors.success, children: [
9570
9337
  " ",
9571
9338
  icons.check,
9572
9339
  " Workflows Enabled"
9573
9340
  ] })
9574
9341
  ] }),
9575
- /* @__PURE__ */ jsx34(Box31, { marginTop: 1, children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9342
+ /* @__PURE__ */ jsx33(Box30, { marginTop: 1, children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9576
9343
  icons.bullet,
9577
9344
  " ",
9578
9345
  workflows.length,
@@ -9580,14 +9347,14 @@ function WorkflowStatusCommand({ projectId }) {
9580
9347
  workflows.length !== 1 ? "s" : "",
9581
9348
  " configured"
9582
9349
  ] }) }),
9583
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: pending.length > 0 ? colors.warning : colors.textMuted, children: [
9350
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: pending.length > 0 ? colors.warning : colors.textMuted, children: [
9584
9351
  icons.bullet,
9585
9352
  " ",
9586
9353
  pending.length,
9587
9354
  " pending approval",
9588
9355
  pending.length !== 1 ? "s" : ""
9589
9356
  ] }) }),
9590
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: locked.length > 0 ? colors.info : colors.textMuted, children: [
9357
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: locked.length > 0 ? colors.info : colors.textMuted, children: [
9591
9358
  icons.bullet,
9592
9359
  " ",
9593
9360
  locked.length,
@@ -9597,15 +9364,15 @@ function WorkflowStatusCommand({ projectId }) {
9597
9364
  ] })
9598
9365
  }
9599
9366
  ),
9600
- workflows.filter((w) => w.is_active).length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: 1, children: [
9601
- /* @__PURE__ */ jsx34(Text32, { bold: true, color: colors.text, children: "Active Workflow" }),
9602
- workflows.filter((w) => w.is_active).map((w) => /* @__PURE__ */ jsxs32(Box31, { marginTop: 1, flexDirection: "column", children: [
9603
- /* @__PURE__ */ jsx34(Text32, { color: colors.primary, children: w.name }),
9604
- /* @__PURE__ */ jsx34(Box31, { marginLeft: 2, flexDirection: "column", children: w.stages.map((stage, i) => /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9367
+ workflows.filter((w) => w.is_active).length > 0 && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: 1, children: [
9368
+ /* @__PURE__ */ jsx33(Text31, { bold: true, color: colors.text, children: "Active Workflow" }),
9369
+ workflows.filter((w) => w.is_active).map((w) => /* @__PURE__ */ jsxs31(Box30, { marginTop: 1, flexDirection: "column", children: [
9370
+ /* @__PURE__ */ jsx33(Text31, { color: colors.primary, children: w.name }),
9371
+ /* @__PURE__ */ jsx33(Box30, { marginLeft: 2, flexDirection: "column", children: w.stages.map((stage, i) => /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9605
9372
  i + 1,
9606
9373
  ". ",
9607
9374
  stage.name,
9608
- stage.required_role && /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
9375
+ stage.required_role && /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9609
9376
  " (requires: ",
9610
9377
  stage.required_role,
9611
9378
  ")"
@@ -9613,56 +9380,56 @@ function WorkflowStatusCommand({ projectId }) {
9613
9380
  ] }) }, stage.id)) })
9614
9381
  ] }, w.id))
9615
9382
  ] }),
9616
- pending.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: 2, children: [
9617
- /* @__PURE__ */ jsxs32(Text32, { bold: true, color: colors.warning, children: [
9383
+ pending.length > 0 && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: 2, children: [
9384
+ /* @__PURE__ */ jsxs31(Text31, { bold: true, color: colors.warning, children: [
9618
9385
  "Pending Approvals (",
9619
9386
  pending.length,
9620
9387
  ")"
9621
9388
  ] }),
9622
- pending.slice(0, 10).map((p) => /* @__PURE__ */ jsxs32(Box31, { marginTop: 1, flexDirection: "column", children: [
9623
- /* @__PURE__ */ jsxs32(Box31, { children: [
9624
- /* @__PURE__ */ jsx34(Text32, { color: colors.text, children: p.key }),
9625
- /* @__PURE__ */ jsxs32(Text32, { color: colors.textDim, children: [
9389
+ pending.slice(0, 10).map((p) => /* @__PURE__ */ jsxs31(Box30, { marginTop: 1, flexDirection: "column", children: [
9390
+ /* @__PURE__ */ jsxs31(Box30, { children: [
9391
+ /* @__PURE__ */ jsx33(Text31, { color: colors.text, children: p.key }),
9392
+ /* @__PURE__ */ jsxs31(Text31, { color: colors.textDim, children: [
9626
9393
  " [",
9627
9394
  p.language,
9628
9395
  "]"
9629
9396
  ] })
9630
9397
  ] }),
9631
- /* @__PURE__ */ jsx34(Box31, { marginLeft: 2, children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9398
+ /* @__PURE__ */ jsx33(Box30, { marginLeft: 2, children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9632
9399
  "Stage: ",
9633
9400
  p.stage_name,
9634
9401
  p.required_role && ` (requires: ${p.required_role})`
9635
9402
  ] }) }),
9636
- /* @__PURE__ */ jsx34(Box31, { marginLeft: 2, children: /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
9403
+ /* @__PURE__ */ jsx33(Box30, { marginLeft: 2, children: /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9637
9404
  "ID: ",
9638
9405
  p.translation_id
9639
9406
  ] }) })
9640
9407
  ] }, p.id)),
9641
- pending.length > 10 && /* @__PURE__ */ jsx34(Box31, { marginTop: 1, children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9408
+ pending.length > 10 && /* @__PURE__ */ jsx33(Box30, { marginTop: 1, children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9642
9409
  "... and ",
9643
9410
  pending.length - 10,
9644
9411
  " more"
9645
9412
  ] }) })
9646
9413
  ] }),
9647
- pending.length === 0 && /* @__PURE__ */ jsx34(Box31, { marginTop: 2, children: /* @__PURE__ */ jsxs32(Text32, { color: colors.success, children: [
9414
+ pending.length === 0 && /* @__PURE__ */ jsx33(Box30, { marginTop: 2, children: /* @__PURE__ */ jsxs31(Text31, { color: colors.success, children: [
9648
9415
  icons.check,
9649
9416
  " No pending approvals"
9650
9417
  ] }) }),
9651
- /* @__PURE__ */ jsx34(Box31, { marginTop: 2, children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9418
+ /* @__PURE__ */ jsx33(Box30, { marginTop: 2, children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9652
9419
  icons.info,
9653
9420
  " Use",
9654
9421
  " ",
9655
- /* @__PURE__ */ jsx34(Text32, { color: colors.primary, children: "npx @intlpullhq/cli workflow approve <id>" }),
9422
+ /* @__PURE__ */ jsx33(Text31, { color: colors.primary, children: "npx @intlpullhq/cli workflow approve <id>" }),
9656
9423
  " to approve"
9657
9424
  ] }) })
9658
9425
  ] })
9659
9426
  ] });
9660
9427
  }
9661
9428
  function WorkflowPendingCommand({ projectId }) {
9662
- const [loading, setLoading] = useState21(true);
9663
- const [error, setError] = useState21(null);
9664
- const [pending, setPending] = useState21([]);
9665
- useEffect18(() => {
9429
+ const [loading, setLoading] = useState20(true);
9430
+ const [error, setError] = useState20(null);
9431
+ const [pending, setPending] = useState20([]);
9432
+ useEffect17(() => {
9666
9433
  async function fetchData() {
9667
9434
  const resolved = getResolvedApiKey();
9668
9435
  if (!resolved?.key) {
@@ -9689,19 +9456,19 @@ function WorkflowPendingCommand({ projectId }) {
9689
9456
  }
9690
9457
  fetchData();
9691
9458
  }, [projectId]);
9692
- return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9693
- /* @__PURE__ */ jsx34(Header, { compact: true }),
9694
- loading && /* @__PURE__ */ jsx34(Box31, { marginY: 1, children: /* @__PURE__ */ jsx34(Spinner2, { label: "Fetching pending approvals..." }) }),
9695
- error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Error", children: error }),
9696
- !loading && !error && pending.length === 0 && /* @__PURE__ */ jsx34(Alert, { type: "success", title: "All Clear", children: "No pending approvals" }),
9697
- !loading && !error && pending.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9698
- /* @__PURE__ */ jsx34(Box31, { marginY: 1, children: /* @__PURE__ */ jsxs32(Text32, { bold: true, color: colors.warning, children: [
9459
+ return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9460
+ /* @__PURE__ */ jsx33(Header, { compact: true }),
9461
+ loading && /* @__PURE__ */ jsx33(Box30, { marginY: 1, children: /* @__PURE__ */ jsx33(Spinner2, { label: "Fetching pending approvals..." }) }),
9462
+ error && /* @__PURE__ */ jsx33(Alert, { type: "error", title: "Error", children: error }),
9463
+ !loading && !error && pending.length === 0 && /* @__PURE__ */ jsx33(Alert, { type: "success", title: "All Clear", children: "No pending approvals" }),
9464
+ !loading && !error && pending.length > 0 && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9465
+ /* @__PURE__ */ jsx33(Box30, { marginY: 1, children: /* @__PURE__ */ jsxs31(Text31, { bold: true, color: colors.warning, children: [
9699
9466
  pending.length,
9700
9467
  " Pending Approval",
9701
9468
  pending.length !== 1 ? "s" : ""
9702
9469
  ] }) }),
9703
- pending.map((p) => /* @__PURE__ */ jsxs32(
9704
- Box31,
9470
+ pending.map((p) => /* @__PURE__ */ jsxs31(
9471
+ Box30,
9705
9472
  {
9706
9473
  borderStyle: "single",
9707
9474
  borderColor: colors.textDim,
@@ -9710,33 +9477,33 @@ function WorkflowPendingCommand({ projectId }) {
9710
9477
  marginBottom: 1,
9711
9478
  flexDirection: "column",
9712
9479
  children: [
9713
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsx34(Text32, { bold: true, color: colors.text, children: p.key }) }),
9714
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9480
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsx33(Text31, { bold: true, color: colors.text, children: p.key }) }),
9481
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9715
9482
  "Language: ",
9716
- /* @__PURE__ */ jsx34(Text32, { color: colors.info, children: p.language }),
9483
+ /* @__PURE__ */ jsx33(Text31, { color: colors.info, children: p.language }),
9717
9484
  " | ",
9718
9485
  "Namespace: ",
9719
- /* @__PURE__ */ jsx34(Text32, { color: colors.info, children: p.namespace })
9486
+ /* @__PURE__ */ jsx33(Text31, { color: colors.info, children: p.namespace })
9720
9487
  ] }) }),
9721
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9488
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9722
9489
  "Stage: ",
9723
- /* @__PURE__ */ jsx34(Text32, { color: colors.warning, children: p.stage_name }),
9724
- p.required_role && /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
9490
+ /* @__PURE__ */ jsx33(Text31, { color: colors.warning, children: p.stage_name }),
9491
+ p.required_role && /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9725
9492
  " (requires: ",
9726
9493
  p.required_role,
9727
9494
  ")"
9728
9495
  ] })
9729
9496
  ] }) }),
9730
- /* @__PURE__ */ jsx34(Box31, { children: /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
9497
+ /* @__PURE__ */ jsx33(Box30, { children: /* @__PURE__ */ jsxs31(Text31, { color: colors.textMuted, children: [
9731
9498
  "Value: ",
9732
- /* @__PURE__ */ jsxs32(Text32, { color: colors.text, children: [
9499
+ /* @__PURE__ */ jsxs31(Text31, { color: colors.text, children: [
9733
9500
  '"',
9734
9501
  p.value.substring(0, 50),
9735
9502
  p.value.length > 50 ? "..." : "",
9736
9503
  '"'
9737
9504
  ] })
9738
9505
  ] }) }),
9739
- /* @__PURE__ */ jsx34(Box31, { marginTop: 1, children: /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
9506
+ /* @__PURE__ */ jsx33(Box30, { marginTop: 1, children: /* @__PURE__ */ jsxs31(Text31, { dimColor: true, children: [
9740
9507
  "ID: ",
9741
9508
  p.translation_id
9742
9509
  ] }) })
@@ -9767,11 +9534,11 @@ The translation is locked and cannot be modified.`;
9767
9534
  return errorMessage;
9768
9535
  }
9769
9536
  function ApproveCommand({ projectId, translationId, comment }) {
9770
- const [loading, setLoading] = useState21(true);
9771
- const [error, setError] = useState21(null);
9772
- const [success, setSuccess] = useState21(false);
9773
- const [stageName, setStageName] = useState21("");
9774
- useEffect18(() => {
9537
+ const [loading, setLoading] = useState20(true);
9538
+ const [error, setError] = useState20(null);
9539
+ const [success, setSuccess] = useState20(false);
9540
+ const [stageName, setStageName] = useState20("");
9541
+ useEffect17(() => {
9775
9542
  async function approve() {
9776
9543
  const resolved = getResolvedApiKey();
9777
9544
  if (!resolved?.key) {
@@ -9800,15 +9567,15 @@ function ApproveCommand({ projectId, translationId, comment }) {
9800
9567
  }
9801
9568
  approve();
9802
9569
  }, [projectId, translationId, comment]);
9803
- return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9804
- /* @__PURE__ */ jsx34(Header, { compact: true }),
9805
- loading && /* @__PURE__ */ jsx34(Box31, { marginY: 1, children: /* @__PURE__ */ jsx34(Spinner2, { label: "Approving translation..." }) }),
9806
- error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Approval Failed", children: error }),
9807
- success && /* @__PURE__ */ jsxs32(Alert, { type: "success", title: "Approved", children: [
9570
+ return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9571
+ /* @__PURE__ */ jsx33(Header, { compact: true }),
9572
+ loading && /* @__PURE__ */ jsx33(Box30, { marginY: 1, children: /* @__PURE__ */ jsx33(Spinner2, { label: "Approving translation..." }) }),
9573
+ error && /* @__PURE__ */ jsx33(Alert, { type: "error", title: "Approval Failed", children: error }),
9574
+ success && /* @__PURE__ */ jsxs31(Alert, { type: "success", title: "Approved", children: [
9808
9575
  'Translation approved at stage "',
9809
9576
  stageName,
9810
9577
  '"',
9811
- comment && /* @__PURE__ */ jsxs32(Fragment5, { children: [
9578
+ comment && /* @__PURE__ */ jsxs31(Fragment5, { children: [
9812
9579
  "\n",
9813
9580
  "Comment: ",
9814
9581
  comment
@@ -9817,10 +9584,10 @@ function ApproveCommand({ projectId, translationId, comment }) {
9817
9584
  ] });
9818
9585
  }
9819
9586
  function RejectCommand({ projectId, translationId, reason }) {
9820
- const [loading, setLoading] = useState21(true);
9821
- const [error, setError] = useState21(null);
9822
- const [success, setSuccess] = useState21(false);
9823
- useEffect18(() => {
9587
+ const [loading, setLoading] = useState20(true);
9588
+ const [error, setError] = useState20(null);
9589
+ const [success, setSuccess] = useState20(false);
9590
+ useEffect17(() => {
9824
9591
  async function reject() {
9825
9592
  const resolved = getResolvedApiKey();
9826
9593
  if (!resolved?.key) {
@@ -9848,11 +9615,11 @@ function RejectCommand({ projectId, translationId, reason }) {
9848
9615
  }
9849
9616
  reject();
9850
9617
  }, [projectId, translationId, reason]);
9851
- return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
9852
- /* @__PURE__ */ jsx34(Header, { compact: true }),
9853
- loading && /* @__PURE__ */ jsx34(Box31, { marginY: 1, children: /* @__PURE__ */ jsx34(Spinner2, { label: "Rejecting translation..." }) }),
9854
- error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Rejection Failed", children: error }),
9855
- success && /* @__PURE__ */ jsxs32(Alert, { type: "warning", title: "Rejected", children: [
9618
+ return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
9619
+ /* @__PURE__ */ jsx33(Header, { compact: true }),
9620
+ loading && /* @__PURE__ */ jsx33(Box30, { marginY: 1, children: /* @__PURE__ */ jsx33(Spinner2, { label: "Rejecting translation..." }) }),
9621
+ error && /* @__PURE__ */ jsx33(Alert, { type: "error", title: "Rejection Failed", children: error }),
9622
+ success && /* @__PURE__ */ jsxs31(Alert, { type: "warning", title: "Rejected", children: [
9856
9623
  'Translation rejected with reason: "',
9857
9624
  reason,
9858
9625
  '"'
@@ -9860,16 +9627,16 @@ function RejectCommand({ projectId, translationId, reason }) {
9860
9627
  ] });
9861
9628
  }
9862
9629
  function runWorkflowStatus(options) {
9863
- render17(/* @__PURE__ */ jsx34(WorkflowStatusCommand, { projectId: options.project }));
9630
+ render16(/* @__PURE__ */ jsx33(WorkflowStatusCommand, { projectId: options.project }));
9864
9631
  }
9865
9632
  function runWorkflowPending(options) {
9866
- render17(/* @__PURE__ */ jsx34(WorkflowPendingCommand, { projectId: options.project }));
9633
+ render16(/* @__PURE__ */ jsx33(WorkflowPendingCommand, { projectId: options.project }));
9867
9634
  }
9868
9635
  function runWorkflowApprove(translationId, options) {
9869
- render17(/* @__PURE__ */ jsx34(ApproveCommand, { projectId: options.project, translationId, comment: options.comment }));
9636
+ render16(/* @__PURE__ */ jsx33(ApproveCommand, { projectId: options.project, translationId, comment: options.comment }));
9870
9637
  }
9871
9638
  function runWorkflowReject(translationId, options) {
9872
- render17(/* @__PURE__ */ jsx34(RejectCommand, { projectId: options.project, translationId, reason: options.reason }));
9639
+ render16(/* @__PURE__ */ jsx33(RejectCommand, { projectId: options.project, translationId, reason: options.reason }));
9873
9640
  }
9874
9641
 
9875
9642
  // src/commands/emails.tsx
@@ -10128,9 +9895,9 @@ async function runEmailsStatus(options) {
10128
9895
  }
10129
9896
 
10130
9897
  // src/commands/zendesk.tsx
10131
- import { useState as useState22, useEffect as useEffect19 } from "react";
10132
- import { render as render18, Box as Box32, Text as Text33 } from "ink";
10133
- import { Fragment as Fragment6, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
9898
+ import { useState as useState21, useEffect as useEffect18 } from "react";
9899
+ import { render as render17, Box as Box31, Text as Text32 } from "ink";
9900
+ import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
10134
9901
  async function fetchZendeskIntegration(apiUrl, apiKey, projectId) {
10135
9902
  const response = await fetch(`${apiUrl}/api/v1/projects/${projectId}/integrations/zendesk`, {
10136
9903
  headers: { Accept: "application/json", "X-API-Key": apiKey }
@@ -10201,11 +9968,11 @@ async function disconnectZendesk(apiUrl, apiKey, projectId) {
10201
9968
  if (!response.ok) throw new Error(`Failed to disconnect: ${response.status}`);
10202
9969
  }
10203
9970
  function ZendeskStatusCommand() {
10204
- const [loading, setLoading] = useState22(true);
10205
- const [integration, setIntegration] = useState22(null);
10206
- const [status, setStatus] = useState22(null);
10207
- const [error, setError] = useState22(null);
10208
- useEffect19(() => {
9971
+ const [loading, setLoading] = useState21(true);
9972
+ const [integration, setIntegration] = useState21(null);
9973
+ const [status, setStatus] = useState21(null);
9974
+ const [error, setError] = useState21(null);
9975
+ useEffect18(() => {
10209
9976
  async function fetch2() {
10210
9977
  const resolved = getResolvedApiKey();
10211
9978
  if (!resolved?.key) {
@@ -10237,54 +10004,54 @@ function ZendeskStatusCommand() {
10237
10004
  }
10238
10005
  fetch2();
10239
10006
  }, []);
10240
- return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10241
- /* @__PURE__ */ jsx35(Header, { compact: true }),
10242
- loading && /* @__PURE__ */ jsx35(Spinner2, { label: "Fetching Zendesk status..." }),
10243
- error && /* @__PURE__ */ jsx35(Alert, { type: "error", title: "Error", children: error }),
10244
- integration && !integration.connected && /* @__PURE__ */ jsx35(Alert, { type: "warning", title: "Not Connected", children: "Zendesk is not connected. Run: npx @intlpullhq/cli zendesk connect --subdomain YOUR_SUBDOMAIN --email YOUR_EMAIL --token YOUR_TOKEN" }),
10245
- integration?.connected && integration.integration && /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginY: 1, children: [
10246
- /* @__PURE__ */ jsx35(Box32, { borderStyle: "round", borderColor: colors.success, paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10247
- /* @__PURE__ */ jsxs33(Text33, { bold: true, color: colors.success, children: [
10007
+ return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10008
+ /* @__PURE__ */ jsx34(Header, { compact: true }),
10009
+ loading && /* @__PURE__ */ jsx34(Spinner2, { label: "Fetching Zendesk status..." }),
10010
+ error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Error", children: error }),
10011
+ integration && !integration.connected && /* @__PURE__ */ jsx34(Alert, { type: "warning", title: "Not Connected", children: "Zendesk is not connected. Run: npx @intlpullhq/cli zendesk connect --subdomain YOUR_SUBDOMAIN --email YOUR_EMAIL --token YOUR_TOKEN" }),
10012
+ integration?.connected && integration.integration && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginY: 1, children: [
10013
+ /* @__PURE__ */ jsx34(Box31, { borderStyle: "round", borderColor: colors.success, paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10014
+ /* @__PURE__ */ jsxs32(Text32, { bold: true, color: colors.success, children: [
10248
10015
  icons.success,
10249
10016
  " Connected to Zendesk"
10250
10017
  ] }),
10251
- /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10018
+ /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10252
10019
  "Subdomain: ",
10253
10020
  integration.integration.subdomain,
10254
10021
  ".zendesk.com"
10255
10022
  ] }),
10256
- /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10023
+ /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10257
10024
  "Source Locale: ",
10258
10025
  integration.integration.source_locale
10259
10026
  ] }),
10260
- integration.integration.last_sync_at && /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10027
+ integration.integration.last_sync_at && /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10261
10028
  "Last Sync: ",
10262
10029
  new Date(integration.integration.last_sync_at).toLocaleString()
10263
10030
  ] })
10264
10031
  ] }) }),
10265
- status && /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: 1, children: [
10266
- /* @__PURE__ */ jsx35(Text33, { bold: true, children: "Content Summary" }),
10267
- /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10032
+ status && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: 1, children: [
10033
+ /* @__PURE__ */ jsx34(Text32, { bold: true, children: "Content Summary" }),
10034
+ /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10268
10035
  icons.bullet,
10269
10036
  " ",
10270
10037
  status.total_articles,
10271
10038
  " articles"
10272
10039
  ] }),
10273
- /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10040
+ /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10274
10041
  icons.bullet,
10275
10042
  " ",
10276
10043
  status.total_categories,
10277
10044
  " categories"
10278
10045
  ] }),
10279
- /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10046
+ /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10280
10047
  icons.bullet,
10281
10048
  " ",
10282
10049
  status.total_sections,
10283
10050
  " sections"
10284
10051
  ] }),
10285
- status.target_locales.length > 0 && /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: 1, children: [
10286
- /* @__PURE__ */ jsx35(Text33, { bold: true, children: "Translation Progress" }),
10287
- status.target_locales.map((locale) => /* @__PURE__ */ jsxs33(Text33, { color: colors.textMuted, children: [
10052
+ status.target_locales.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: 1, children: [
10053
+ /* @__PURE__ */ jsx34(Text32, { bold: true, children: "Translation Progress" }),
10054
+ status.target_locales.map((locale) => /* @__PURE__ */ jsxs32(Text32, { color: colors.textMuted, children: [
10288
10055
  icons.bullet,
10289
10056
  " ",
10290
10057
  locale,
@@ -10300,10 +10067,10 @@ function ZendeskStatusCommand() {
10300
10067
  ] });
10301
10068
  }
10302
10069
  function ZendeskConnectCommand({ subdomain, email, token }) {
10303
- const [loading, setLoading] = useState22(true);
10304
- const [result, setResult] = useState22(null);
10305
- const [error, setError] = useState22(null);
10306
- useEffect19(() => {
10070
+ const [loading, setLoading] = useState21(true);
10071
+ const [result, setResult] = useState21(null);
10072
+ const [error, setError] = useState21(null);
10073
+ useEffect18(() => {
10307
10074
  async function connect() {
10308
10075
  const resolved = getResolvedApiKey();
10309
10076
  if (!resolved?.key) {
@@ -10331,11 +10098,11 @@ function ZendeskConnectCommand({ subdomain, email, token }) {
10331
10098
  }
10332
10099
  connect();
10333
10100
  }, [subdomain, email, token]);
10334
- return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10335
- /* @__PURE__ */ jsx35(Header, { compact: true }),
10336
- loading && /* @__PURE__ */ jsx35(Spinner2, { label: "Connecting to Zendesk..." }),
10337
- error && /* @__PURE__ */ jsx35(Alert, { type: "error", title: "Connection Failed", children: error }),
10338
- result?.connected && /* @__PURE__ */ jsxs33(Alert, { type: "success", title: "Connected!", children: [
10101
+ return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10102
+ /* @__PURE__ */ jsx34(Header, { compact: true }),
10103
+ loading && /* @__PURE__ */ jsx34(Spinner2, { label: "Connecting to Zendesk..." }),
10104
+ error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Connection Failed", children: error }),
10105
+ result?.connected && /* @__PURE__ */ jsxs32(Alert, { type: "success", title: "Connected!", children: [
10339
10106
  "Successfully connected to ",
10340
10107
  subdomain,
10341
10108
  ".zendesk.com",
@@ -10345,10 +10112,10 @@ function ZendeskConnectCommand({ subdomain, email, token }) {
10345
10112
  ] });
10346
10113
  }
10347
10114
  function ZendeskSyncCommand({ direction, locale, excludeDrafts, autoTranslate, translateProvider }) {
10348
- const [loading, setLoading] = useState22(true);
10349
- const [result, setResult] = useState22(null);
10350
- const [error, setError] = useState22(null);
10351
- useEffect19(() => {
10115
+ const [loading, setLoading] = useState21(true);
10116
+ const [result, setResult] = useState21(null);
10117
+ const [error, setError] = useState21(null);
10118
+ useEffect18(() => {
10352
10119
  async function sync() {
10353
10120
  const resolved = getResolvedApiKey();
10354
10121
  if (!resolved?.key) {
@@ -10390,11 +10157,11 @@ function ZendeskSyncCommand({ direction, locale, excludeDrafts, autoTranslate, t
10390
10157
  }
10391
10158
  sync();
10392
10159
  }, [direction, locale, excludeDrafts, autoTranslate, translateProvider]);
10393
- return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10394
- /* @__PURE__ */ jsx35(Header, { compact: true }),
10395
- loading && /* @__PURE__ */ jsx35(Spinner2, { label: `${direction === "pull" ? "Pulling from" : "Pushing to"} Zendesk...${autoTranslate ? " (with auto-translation)" : ""}` }),
10396
- error && /* @__PURE__ */ jsx35(Alert, { type: "error", title: "Sync Failed", children: error }),
10397
- result?.success && /* @__PURE__ */ jsx35(Alert, { type: "success", title: "Sync Complete", children: direction === "pull" ? /* @__PURE__ */ jsxs33(Fragment6, { children: [
10160
+ return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10161
+ /* @__PURE__ */ jsx34(Header, { compact: true }),
10162
+ loading && /* @__PURE__ */ jsx34(Spinner2, { label: `${direction === "pull" ? "Pulling from" : "Pushing to"} Zendesk...${autoTranslate ? " (with auto-translation)" : ""}` }),
10163
+ error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Sync Failed", children: error }),
10164
+ result?.success && /* @__PURE__ */ jsx34(Alert, { type: "success", title: "Sync Complete", children: direction === "pull" ? /* @__PURE__ */ jsxs32(Fragment6, { children: [
10398
10165
  "Imported ",
10399
10166
  result.articles_synced,
10400
10167
  " articles, ",
@@ -10407,24 +10174,24 @@ function ZendeskSyncCommand({ direction, locale, excludeDrafts, autoTranslate, t
10407
10174
  result.keys_created,
10408
10175
  ", updated: ",
10409
10176
  result.keys_updated,
10410
- result.auto_translate_job && /* @__PURE__ */ jsxs33(Fragment6, { children: [
10177
+ result.auto_translate_job && /* @__PURE__ */ jsxs32(Fragment6, { children: [
10411
10178
  "\n",
10412
10179
  "Auto-translation started: ",
10413
10180
  result.auto_translate_job
10414
10181
  ] })
10415
- ] }) : /* @__PURE__ */ jsxs33(Fragment6, { children: [
10182
+ ] }) : /* @__PURE__ */ jsxs32(Fragment6, { children: [
10416
10183
  "Pushed translations for ",
10417
10184
  result.articles_synced,
10418
10185
  " articles to Zendesk"
10419
10186
  ] }) }),
10420
- result && !result.success && /* @__PURE__ */ jsx35(Alert, { type: "error", title: "Sync Failed", children: result.error || "Unknown error" })
10187
+ result && !result.success && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Sync Failed", children: result.error || "Unknown error" })
10421
10188
  ] });
10422
10189
  }
10423
10190
  function ZendeskDisconnectCommand() {
10424
- const [loading, setLoading] = useState22(true);
10425
- const [success, setSuccess] = useState22(false);
10426
- const [error, setError] = useState22(null);
10427
- useEffect19(() => {
10191
+ const [loading, setLoading] = useState21(true);
10192
+ const [success, setSuccess] = useState21(false);
10193
+ const [error, setError] = useState21(null);
10194
+ useEffect18(() => {
10428
10195
  async function disconnect() {
10429
10196
  const resolved = getResolvedApiKey();
10430
10197
  if (!resolved?.key) {
@@ -10452,22 +10219,22 @@ function ZendeskDisconnectCommand() {
10452
10219
  }
10453
10220
  disconnect();
10454
10221
  }, []);
10455
- return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10456
- /* @__PURE__ */ jsx35(Header, { compact: true }),
10457
- loading && /* @__PURE__ */ jsx35(Spinner2, { label: "Disconnecting..." }),
10458
- error && /* @__PURE__ */ jsx35(Alert, { type: "error", title: "Error", children: error }),
10459
- success && /* @__PURE__ */ jsx35(Alert, { type: "success", title: "Disconnected", children: "Zendesk integration has been removed." })
10222
+ return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10223
+ /* @__PURE__ */ jsx34(Header, { compact: true }),
10224
+ loading && /* @__PURE__ */ jsx34(Spinner2, { label: "Disconnecting..." }),
10225
+ error && /* @__PURE__ */ jsx34(Alert, { type: "error", title: "Error", children: error }),
10226
+ success && /* @__PURE__ */ jsx34(Alert, { type: "success", title: "Disconnected", children: "Zendesk integration has been removed." })
10460
10227
  ] });
10461
10228
  }
10462
10229
  function runZendeskStatus() {
10463
- render18(/* @__PURE__ */ jsx35(ZendeskStatusCommand, {}));
10230
+ render17(/* @__PURE__ */ jsx34(ZendeskStatusCommand, {}));
10464
10231
  }
10465
10232
  function runZendeskConnect(options) {
10466
10233
  if (!options.subdomain || !options.email || !options.token) {
10467
- render18(
10468
- /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10469
- /* @__PURE__ */ jsx35(Header, { compact: true }),
10470
- /* @__PURE__ */ jsxs33(Alert, { type: "error", title: "Missing Options", children: [
10234
+ render17(
10235
+ /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
10236
+ /* @__PURE__ */ jsx34(Header, { compact: true }),
10237
+ /* @__PURE__ */ jsxs32(Alert, { type: "error", title: "Missing Options", children: [
10471
10238
  "Required: --subdomain, --email, --token",
10472
10239
  "\n",
10473
10240
  "Example: npx @intlpullhq/cli zendesk connect --subdomain mycompany --email admin@example.com --token YOUR_API_TOKEN"
@@ -10476,12 +10243,12 @@ function runZendeskConnect(options) {
10476
10243
  );
10477
10244
  return;
10478
10245
  }
10479
- render18(/* @__PURE__ */ jsx35(ZendeskConnectCommand, { subdomain: options.subdomain, email: options.email, token: options.token }));
10246
+ render17(/* @__PURE__ */ jsx34(ZendeskConnectCommand, { subdomain: options.subdomain, email: options.email, token: options.token }));
10480
10247
  }
10481
10248
  function runZendeskSync(options) {
10482
10249
  const direction = options.direction || "pull";
10483
- render18(
10484
- /* @__PURE__ */ jsx35(
10250
+ render17(
10251
+ /* @__PURE__ */ jsx34(
10485
10252
  ZendeskSyncCommand,
10486
10253
  {
10487
10254
  direction,
@@ -10494,17 +10261,17 @@ function runZendeskSync(options) {
10494
10261
  );
10495
10262
  }
10496
10263
  function runZendeskDisconnect() {
10497
- render18(/* @__PURE__ */ jsx35(ZendeskDisconnectCommand, {}));
10264
+ render17(/* @__PURE__ */ jsx34(ZendeskDisconnectCommand, {}));
10498
10265
  }
10499
10266
 
10500
10267
  // src/commands/documents/index.tsx
10501
10268
  import { Command } from "commander";
10502
10269
 
10503
10270
  // src/commands/documents/list.tsx
10504
- import { useState as useState23, useEffect as useEffect20 } from "react";
10505
- import { render as render19, Box as Box33, Text as Text34, Newline } from "ink";
10506
- import Spinner16 from "ink-spinner";
10507
- import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
10271
+ import { useState as useState22, useEffect as useEffect19 } from "react";
10272
+ import { render as render18, Box as Box32, Text as Text33, Newline } from "ink";
10273
+ import Spinner15 from "ink-spinner";
10274
+ import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
10508
10275
  function SimpleTable({ data }) {
10509
10276
  if (data.length === 0) return null;
10510
10277
  const headers = Object.keys(data[0]);
@@ -10512,27 +10279,27 @@ function SimpleTable({ data }) {
10512
10279
  (h) => Math.max(h.length, ...data.map((row) => String(row[h] || "").length))
10513
10280
  );
10514
10281
  const separator = "\u2500".repeat(colWidths.reduce((a, b) => a + b + 3, 1));
10515
- return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
10516
- /* @__PURE__ */ jsx36(Text34, { children: separator }),
10517
- /* @__PURE__ */ jsxs34(Text34, { children: [
10282
+ return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10283
+ /* @__PURE__ */ jsx35(Text33, { children: separator }),
10284
+ /* @__PURE__ */ jsxs33(Text33, { children: [
10518
10285
  "\u2502 ",
10519
10286
  headers.map((h, i) => h.padEnd(colWidths[i])).join(" \u2502 "),
10520
10287
  " \u2502"
10521
10288
  ] }),
10522
- /* @__PURE__ */ jsx36(Text34, { children: separator }),
10523
- data.map((row, rowIdx) => /* @__PURE__ */ jsxs34(Text34, { children: [
10289
+ /* @__PURE__ */ jsx35(Text33, { children: separator }),
10290
+ data.map((row, rowIdx) => /* @__PURE__ */ jsxs33(Text33, { children: [
10524
10291
  "\u2502 ",
10525
10292
  headers.map((h, i) => String(row[h] || "").padEnd(colWidths[i])).join(" \u2502 "),
10526
10293
  " \u2502"
10527
10294
  ] }, rowIdx)),
10528
- /* @__PURE__ */ jsx36(Text34, { children: separator })
10295
+ /* @__PURE__ */ jsx35(Text33, { children: separator })
10529
10296
  ] });
10530
10297
  }
10531
10298
  var DocumentsList = ({ project }) => {
10532
- const [documents, setDocuments] = useState23([]);
10533
- const [isLoading, setIsLoading] = useState23(true);
10534
- const [error, setError] = useState23(null);
10535
- useEffect20(() => {
10299
+ const [documents, setDocuments] = useState22([]);
10300
+ const [isLoading, setIsLoading] = useState22(true);
10301
+ const [error, setError] = useState22(null);
10302
+ useEffect19(() => {
10536
10303
  const fetchDocuments = async () => {
10537
10304
  try {
10538
10305
  const config = getProjectConfig();
@@ -10554,19 +10321,19 @@ var DocumentsList = ({ project }) => {
10554
10321
  fetchDocuments();
10555
10322
  }, [project]);
10556
10323
  if (error) {
10557
- return /* @__PURE__ */ jsxs34(Text34, { color: "red", children: [
10324
+ return /* @__PURE__ */ jsxs33(Text33, { color: "red", children: [
10558
10325
  "Error: ",
10559
10326
  error
10560
10327
  ] });
10561
10328
  }
10562
10329
  if (isLoading) {
10563
- return /* @__PURE__ */ jsxs34(Text34, { children: [
10564
- /* @__PURE__ */ jsx36(Text34, { color: "green", children: /* @__PURE__ */ jsx36(Spinner16, { type: "dots" }) }),
10330
+ return /* @__PURE__ */ jsxs33(Text33, { children: [
10331
+ /* @__PURE__ */ jsx35(Text33, { color: "green", children: /* @__PURE__ */ jsx35(Spinner15, { type: "dots" }) }),
10565
10332
  " Loading documents..."
10566
10333
  ] });
10567
10334
  }
10568
10335
  if (documents.length === 0) {
10569
- return /* @__PURE__ */ jsx36(Text34, { children: "No documents found." });
10336
+ return /* @__PURE__ */ jsx35(Text33, { children: "No documents found." });
10570
10337
  }
10571
10338
  const data = documents.map((doc) => ({
10572
10339
  ID: doc.id.substring(0, 8) + "...",
@@ -10574,30 +10341,30 @@ var DocumentsList = ({ project }) => {
10574
10341
  Status: doc.status,
10575
10342
  Created: new Date(doc.created_at).toLocaleDateString()
10576
10343
  }));
10577
- return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
10578
- /* @__PURE__ */ jsxs34(Text34, { children: [
10344
+ return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
10345
+ /* @__PURE__ */ jsxs33(Text33, { children: [
10579
10346
  "Target Project: ",
10580
10347
  project || "Current"
10581
10348
  ] }),
10582
- /* @__PURE__ */ jsx36(Newline, {}),
10583
- /* @__PURE__ */ jsx36(SimpleTable, { data })
10349
+ /* @__PURE__ */ jsx35(Newline, {}),
10350
+ /* @__PURE__ */ jsx35(SimpleTable, { data })
10584
10351
  ] });
10585
10352
  };
10586
10353
  function runDocumentsList(options) {
10587
- render19(/* @__PURE__ */ jsx36(DocumentsList, { ...options }));
10354
+ render18(/* @__PURE__ */ jsx35(DocumentsList, { ...options }));
10588
10355
  }
10589
10356
 
10590
10357
  // src/commands/documents/upload.tsx
10591
- import { useState as useState24, useEffect as useEffect21 } from "react";
10592
- import { render as render20, Text as Text35 } from "ink";
10593
- import Spinner17 from "ink-spinner";
10358
+ import { useState as useState23, useEffect as useEffect20 } from "react";
10359
+ import { render as render19, Text as Text34 } from "ink";
10360
+ import Spinner16 from "ink-spinner";
10594
10361
  import fs2 from "fs";
10595
10362
  import path2 from "path";
10596
- import { jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
10363
+ import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
10597
10364
  var DocumentsUpload = ({ file, project, source, target }) => {
10598
- const [status, setStatus] = useState24("uploading");
10599
- const [message, setMessage] = useState24("Uploading document...");
10600
- useEffect21(() => {
10365
+ const [status, setStatus] = useState23("uploading");
10366
+ const [message, setMessage] = useState23("Uploading document...");
10367
+ useEffect20(() => {
10601
10368
  const upload = async () => {
10602
10369
  try {
10603
10370
  const config = getProjectConfig();
@@ -10628,38 +10395,38 @@ var DocumentsUpload = ({ file, project, source, target }) => {
10628
10395
  upload();
10629
10396
  }, [file, project, source, target]);
10630
10397
  if (status === "error") {
10631
- return /* @__PURE__ */ jsxs35(Text35, { color: "red", children: [
10398
+ return /* @__PURE__ */ jsxs34(Text34, { color: "red", children: [
10632
10399
  "Error: ",
10633
10400
  message
10634
10401
  ] });
10635
10402
  }
10636
10403
  if (status === "success") {
10637
- return /* @__PURE__ */ jsxs35(Text35, { color: "green", children: [
10404
+ return /* @__PURE__ */ jsxs34(Text34, { color: "green", children: [
10638
10405
  "\u2713 ",
10639
10406
  message
10640
10407
  ] });
10641
10408
  }
10642
- return /* @__PURE__ */ jsxs35(Text35, { children: [
10643
- /* @__PURE__ */ jsx37(Text35, { color: "green", children: /* @__PURE__ */ jsx37(Spinner17, { type: "dots" }) }),
10409
+ return /* @__PURE__ */ jsxs34(Text34, { children: [
10410
+ /* @__PURE__ */ jsx36(Text34, { color: "green", children: /* @__PURE__ */ jsx36(Spinner16, { type: "dots" }) }),
10644
10411
  " ",
10645
10412
  message
10646
10413
  ] });
10647
10414
  };
10648
10415
  function runDocumentsUpload(options) {
10649
- render20(/* @__PURE__ */ jsx37(DocumentsUpload, { ...options }));
10416
+ render19(/* @__PURE__ */ jsx36(DocumentsUpload, { ...options }));
10650
10417
  }
10651
10418
 
10652
10419
  // src/commands/documents/download.tsx
10653
- import { useState as useState25, useEffect as useEffect22 } from "react";
10654
- import { render as render21, Text as Text36 } from "ink";
10655
- import Spinner18 from "ink-spinner";
10420
+ import { useState as useState24, useEffect as useEffect21 } from "react";
10421
+ import { render as render20, Text as Text35 } from "ink";
10422
+ import Spinner17 from "ink-spinner";
10656
10423
  import fs3 from "fs";
10657
10424
  import path3 from "path";
10658
- import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
10425
+ import { jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
10659
10426
  var DocumentsDownload = ({ documentId, language, project, output }) => {
10660
- const [status, setStatus] = useState25("downloading");
10661
- const [message, setMessage] = useState25("Downloading document...");
10662
- useEffect22(() => {
10427
+ const [status, setStatus] = useState24("downloading");
10428
+ const [message, setMessage] = useState24("Downloading document...");
10429
+ useEffect21(() => {
10663
10430
  const download = async () => {
10664
10431
  try {
10665
10432
  const config = getProjectConfig();
@@ -10689,25 +10456,25 @@ var DocumentsDownload = ({ documentId, language, project, output }) => {
10689
10456
  download();
10690
10457
  }, [documentId, language, project, output]);
10691
10458
  if (status === "error") {
10692
- return /* @__PURE__ */ jsxs36(Text36, { color: "red", children: [
10459
+ return /* @__PURE__ */ jsxs35(Text35, { color: "red", children: [
10693
10460
  "Error: ",
10694
10461
  message
10695
10462
  ] });
10696
10463
  }
10697
10464
  if (status === "success") {
10698
- return /* @__PURE__ */ jsxs36(Text36, { color: "green", children: [
10465
+ return /* @__PURE__ */ jsxs35(Text35, { color: "green", children: [
10699
10466
  "\u2713 ",
10700
10467
  message
10701
10468
  ] });
10702
10469
  }
10703
- return /* @__PURE__ */ jsxs36(Text36, { children: [
10704
- /* @__PURE__ */ jsx38(Text36, { color: "green", children: /* @__PURE__ */ jsx38(Spinner18, { type: "dots" }) }),
10470
+ return /* @__PURE__ */ jsxs35(Text35, { children: [
10471
+ /* @__PURE__ */ jsx37(Text35, { color: "green", children: /* @__PURE__ */ jsx37(Spinner17, { type: "dots" }) }),
10705
10472
  " ",
10706
10473
  message
10707
10474
  ] });
10708
10475
  };
10709
10476
  function runDocumentsDownload(options) {
10710
- render21(/* @__PURE__ */ jsx38(DocumentsDownload, { ...options }));
10477
+ render20(/* @__PURE__ */ jsx37(DocumentsDownload, { ...options }));
10711
10478
  }
10712
10479
 
10713
10480
  // src/commands/documents/index.tsx
@@ -10915,15 +10682,6 @@ migrate.command("from <provider>").description("Migrate from Lokalise, Crowdin,
10915
10682
  dryRun: options.dryRun
10916
10683
  });
10917
10684
  });
10918
- program.command("compare").description("Compare pricing with Lokalise, Crowdin, Phrase").option("--from <provider>", "Specific competitor to compare (lokalise, crowdin, phrase)").option("--keys <n>", "Number of translation keys", "5000").option("--languages <n>", "Number of languages", "3").option("--users <n>", "Number of team members", "5").option("--json", "Output as JSON", false).action((options) => {
10919
- runCompare({
10920
- from: options.from,
10921
- keys: parseInt(options.keys, 10),
10922
- languages: parseInt(options.languages, 10),
10923
- users: parseInt(options.users, 10),
10924
- json: options.json
10925
- });
10926
- });
10927
10685
  program.command("check").description("Check for missing translations").option("--source <lang>", "Source language", "en").option("--target <langs>", "Target languages (comma-separated)").option("--output <file>", "Output report file").option("--fix", "Auto-fix missing translations", false).action((options) => {
10928
10686
  runCheck({
10929
10687
  source: options.source,